├── VERSION ├── server ├── config.xml ├── eula.txt ├── launch.sh └── server.properties ├── images └── logo.png ├── fabric ├── fabric-api-0.100.3+1.21.jar └── fabric-server-mc.1.21-loader.0.16.5-launcher.1.0.1.jar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ ├── resources │ │ ├── assets │ │ │ ├── modid │ │ │ │ └── icon.png │ │ │ └── minecraft │ │ │ │ └── shaders │ │ │ │ └── core │ │ │ │ ├── annotate_position.vsh │ │ │ │ ├── annotate_position_color.vsh │ │ │ │ ├── annotate_position_tex_color.vsh │ │ │ │ ├── annotate_position_tex.vsh │ │ │ │ ├── annotate_position.json │ │ │ │ ├── annotate_position_tex.json │ │ │ │ ├── annotate_position_color.json │ │ │ │ ├── annotate_position_tex_color.json │ │ │ │ └── annotate.fsh │ │ ├── vereya.accesswidener │ │ ├── fabric.mod.json │ │ ├── vereya.mixins.json │ │ └── Schemas │ │ │ ├── MissionEnded.xsd │ │ │ └── MissionInit.xsd │ └── java │ │ └── io │ │ └── singularitynet │ │ ├── Client │ │ ├── IMissionBehaviour.java │ │ ├── VideoProducedObserver.java │ │ ├── IMalmoModClient.java │ │ └── ClientState.java │ │ ├── MissionHandlerInterfaces │ │ ├── IAudioProducer.java │ │ ├── ClientChatListener.java │ │ ├── IObservationProducer.java │ │ ├── IRewardProducer.java │ │ ├── IWantToQuit.java │ │ ├── ICommandHandler.java │ │ ├── IWorldDecorator.java │ │ ├── IVideoProducer.java │ │ └── IWorldGenerator.java │ │ ├── NetworkConstants.java │ │ ├── utils │ │ ├── IScreenHelper.java │ │ ├── ScreenHelper.java │ │ └── AddressHelper.java │ │ ├── IVereyaMessageListener.java │ │ ├── mixin │ │ ├── SessionMixin.java │ │ ├── MouseAccessorMixin.java │ │ ├── InGameHudMixin.java │ │ ├── ServerEntityManagerMixin.java │ │ ├── ClientWorldMixinAccess.java │ │ ├── LevelStorageMixin.java │ │ ├── LootTableProviderMixin.java │ │ ├── MinecraftClientMixin.java │ │ ├── ServerPlayNetworkHandlerMixin.java │ │ ├── MobEntityAccessorMixin.java │ │ ├── GlUniformChunkOffsetMixin.java │ │ ├── MinecraftClientEventsMixin.java │ │ ├── GlStateManagerBindTextureMixin.java │ │ ├── RenderSystemTextureGlMixin.java │ │ ├── TitleScreenMixin.java │ │ ├── EntityRenderDispatcherAccessor.java │ │ ├── ServerWorldMixin.java │ │ ├── RenderSystemTextureMixin.java │ │ ├── ServerWorldEntityLoaderMixin.java │ │ ├── EntityMixin.java │ │ ├── WorldRendererSkyMixin.java │ │ ├── MinecraftClientFramebufferMixin.java │ │ ├── TextureManagerMixin.java │ │ ├── MouseMixin.java │ │ ├── WorldRendererShaderMixin.java │ │ ├── MobEntityMixin.java │ │ ├── EntityRenderDispatcherMixin.java │ │ ├── KeyBindingMixin.java │ │ ├── EntityRenderDispatcherShadowMixin.java │ │ ├── RenderSystemShaderSwapMixin.java │ │ ├── FeatureRendererMixin.java │ │ ├── GlStateManagerDrawMixin.java │ │ ├── WorldRendererColourmapMixin.java │ │ ├── EntityRendererMixin.java │ │ ├── VertexBufferMixin.java │ │ ├── GameOptionsMixin.java │ │ ├── BlockRenderManagerMixin.java │ │ └── RenderSystemDrawMixin.java │ │ ├── TitleScreenEvents.java │ │ ├── events │ │ ├── ScreenEvents.java │ │ └── ServerEntityEventsVereya.java │ │ ├── Server │ │ └── ServerState.java │ │ ├── EventWrapper.java │ │ ├── MyChatHud.java │ │ ├── MessagePayload.java │ │ ├── MissionHandlers │ │ ├── DiscreteMovementCommandsImplementation.java │ │ ├── HandlerBase.java │ │ ├── CommandForAttackAndUseImplementation.java │ │ ├── CommandForHotBarKeysImplementation.java │ │ ├── RewardForSendingCommandImplementation.java │ │ ├── CommandForDiscreteRobotNavigationImplementation.java │ │ ├── ObservationFromHotBarImplementation.java │ │ ├── RewardGroup.java │ │ ├── ObservationFromItemsImplementation.java │ │ ├── CommandForWheeledRobotNavigationMobImplementation.java │ │ ├── BlockPlaceCommandsImplementation.java │ │ ├── ContinuousMovementCommandsImplementation.java │ │ ├── ObservationFromFullStatsImplementation.java │ │ ├── VideoProducerImplementation.java │ │ ├── AgentQuitFromTouchingBlockTypeImplementation.java │ │ ├── ObservationFromSolidnessImplementation.java │ │ ├── WorldUtil.java │ │ ├── ObservationFromRecipesImplementation.java │ │ ├── SimpleCraftCommandsImplementation.java │ │ ├── ObservationFromComposite.java │ │ ├── RewardForTouchingBlockTypeImplementation.java │ │ ├── ChatCommandsImplementation.java │ │ ├── ObservationFromChatImplementation.java │ │ ├── SimpleCraftCommandsImplementationServer.java │ │ ├── FlatWorldGeneratorImplementation.java │ │ └── CommandBase.java │ │ ├── IState.java │ │ ├── VereyaMessageType.java │ │ └── EpisodeEventWrapper.java └── test │ ├── java │ └── io │ │ └── singularitynet │ │ └── tests │ │ ├── FrameType.java │ │ ├── TimestampedByteVector.java │ │ ├── MinecraftSegmentationIT.java │ │ ├── StringServer.java │ │ ├── VideoServer.java │ │ └── TCPServer.java │ └── resources │ └── mission.xml ├── jars └── vereya-fabric_0.100.3+1.21-0.1.7.jar ├── settings.gradle ├── .gitignore ├── gradle.properties ├── config.xml ├── readme.md ├── gradlew.bat ├── .github └── workflows │ └── build.yml └── api.md /VERSION: -------------------------------------------------------------------------------- 1 | 0.1.8 2 | -------------------------------------------------------------------------------- /server/config.xml: -------------------------------------------------------------------------------- 1 | ../config.xml -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/images/logo.png -------------------------------------------------------------------------------- /fabric/fabric-api-0.100.3+1.21.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/fabric/fabric-api-0.100.3+1.21.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/modid/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/src/main/resources/assets/modid/icon.png -------------------------------------------------------------------------------- /jars/vereya-fabric_0.100.3+1.21-0.1.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/jars/vereya-fabric_0.100.3+1.21-0.1.7.jar -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/Client/IMissionBehaviour.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.Client; 2 | 3 | public interface IMissionBehaviour { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /fabric/fabric-server-mc.1.21-loader.0.16.5-launcher.1.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trueagi-io/Vereya/HEAD/fabric/fabric-server-mc.1.21-loader.0.16.5-launcher.1.0.1.jar -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IAudioProducer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | public interface IAudioProducer { 4 | } 5 | -------------------------------------------------------------------------------- /server/eula.txt: -------------------------------------------------------------------------------- 1 | #By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA). 2 | #Thu Dec 29 16:39:29 GMT+04:00 2022 3 | eula=true 4 | -------------------------------------------------------------------------------- /server/launch.sh: -------------------------------------------------------------------------------- 1 | java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8006 -Dlog4j.configurationFile=`pwd`/config.xml -Xmx2G -jar mods/fabric-server-mc.1.21-loader.0.16.5-launcher.1.0.1.jar --nogui 2 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/FrameType.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | public enum FrameType { 4 | VIDEO, 5 | DEPTH_MAP, 6 | LUMINANCE, 7 | COLOUR_MAP 8 | } 9 | 10 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/ClientChatListener.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import net.minecraft.text.Text; 4 | 5 | public interface ClientChatListener { 6 | void onChatMessage(Text message); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/Client/VideoProducedObserver.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.Client; 2 | 3 | /** 4 | * VideoProducedObserver - for notifying that a video frame has been produced. 5 | */ 6 | public interface VideoProducedObserver { 7 | void frameProduced(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/Client/IMalmoModClient.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.Client; 2 | 3 | public interface IMalmoModClient { 4 | public void setInputType(VereyaModClient.InputType input); 5 | public void setup(); 6 | public VereyaModClient.InputType getInputType(); 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/NetworkConstants.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import net.minecraft.util.Identifier; 4 | 5 | public class NetworkConstants { 6 | public static Identifier SERVER2CLIENT = Identifier.ofVanilla("server2client"); 7 | public static Identifier CLIENT2SERVER = Identifier.ofVanilla("client2server"); 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | -------------------------------------------------------------------------------- /src/main/resources/vereya.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v2 named 2 | 3 | accessible class net/minecraft/client/network/ClientLoginNetworkHandler$State 4 | accessible field net/minecraft/client/network/ClientLoginNetworkHandler$State name Lnet/minecraft/text/Text; 5 | accessible field net/minecraft/client/network/ClientLoginNetworkHandler$State prevStates Ljava/util/Set; -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/utils/IScreenHelper.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.utils; 2 | 3 | import io.singularitynet.utils.ScreenHelper.TextCategory; 4 | 5 | public interface IScreenHelper { 6 | 7 | void clearFragment(String infoReserveStatus); 8 | 9 | public void addFragment(String text, TextCategory category, String handle); 10 | public void addFragment(String text, TextCategory category, int handle); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/IVereyaMessageListener.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import net.minecraft.server.network.ServerPlayerEntity; 4 | 5 | import java.util.Map; 6 | 7 | 8 | public interface IVereyaMessageListener 9 | { 10 | void onMessage(VereyaMessageType messageType, Map data); 11 | void onMessage(VereyaMessageType messageType, Map data, ServerPlayerEntity player); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/SessionMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.client.session.Session; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Mutable; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(Session.class) 9 | public interface SessionMixin { 10 | @Accessor("username") @Mutable 11 | public void setName(String name); 12 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/develop 6 | minecraft_version=1.21 7 | yarn_mappings=1.21+build.2 8 | loader_version=0.15.11 9 | 10 | # Mod Properties 11 | mod_version = 1.0.0 12 | maven_group = io.singularitynet 13 | archives_base_name = vereya 14 | 15 | #Fabric api 16 | fabric_version=0.100.3+1.21 -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IObservationProducer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import com.google.gson.JsonObject; 4 | import io.singularitynet.projectmalmo.MissionInit; 5 | 6 | public interface IObservationProducer { 7 | public void cleanup(); 8 | public void prepare(MissionInit missionInit); 9 | 10 | void writeObservationsToJSON(JsonObject json, MissionInit currentMissionInit); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MouseAccessorMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | 4 | import net.minecraft.client.Mouse; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(Mouse.class) 9 | public interface MouseAccessorMixin { 10 | @Accessor("cursorDeltaX") 11 | public double getCursorDeltaX(); 12 | @Accessor("cursorDeltaY") 13 | public double getCursorDeltaY(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position.vsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 Position; 4 | 5 | uniform mat4 ModelViewMat; 6 | uniform mat4 ProjMat; 7 | uniform vec3 ChunkOffset; 8 | 9 | out vec2 texCoord0; 10 | out vec4 vertexColor; 11 | 12 | void main() { 13 | vec3 worldPos = Position + ChunkOffset; 14 | gl_Position = ProjMat * ModelViewMat * vec4(worldPos, 1.0); 15 | texCoord0 = vec2(0.0); 16 | vertexColor = vec4(1.0); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_color.vsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 Position; 4 | in vec4 Color; 5 | 6 | uniform mat4 ModelViewMat; 7 | uniform mat4 ProjMat; 8 | uniform vec3 ChunkOffset; 9 | 10 | out vec2 texCoord0; 11 | out vec4 vertexColor; 12 | 13 | void main() { 14 | vec3 worldPos = Position + ChunkOffset; 15 | gl_Position = ProjMat * ModelViewMat * vec4(worldPos, 1.0); 16 | texCoord0 = vec2(0.0); 17 | vertexColor = Color; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IRewardProducer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import io.singularitynet.MissionHandlers.MultidimensionalReward; 4 | import io.singularitynet.projectmalmo.MissionInit; 5 | 6 | public interface IRewardProducer { 7 | public void cleanup(); 8 | public void prepare(MissionInit missionInit); 9 | public void getReward(MultidimensionalReward reward); 10 | public void trigger(Class clazz); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/InGameHudMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.client.gui.hud.ChatHud; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Mutable; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | import net.minecraft.client.gui.hud.InGameHud; 8 | 9 | @Mixin(InGameHud.class) 10 | public interface InGameHudMixin { 11 | @Accessor("chatHud") @Mutable 12 | public void setChatHud(ChatHud hud); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/ServerEntityManagerMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.server.world.ServerEntityManager; 4 | import net.minecraft.world.entity.EntityLike; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | @Mixin(ServerEntityManager.class) 9 | public interface ServerEntityManagerMixin { 10 | 11 | @Invoker("stopTracking") 12 | public void stopTracking(T entity); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/ClientWorldMixinAccess.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.world.entity.ClientEntityManager; 4 | import net.minecraft.client.world.ClientWorld; 5 | import net.minecraft.entity.Entity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | @Mixin(ClientWorld.class) 10 | public interface ClientWorldMixinAccess { 11 | 12 | @Accessor("entityManager") 13 | ClientEntityManager getEntityManager(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/TimestampedByteVector.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | /** Simple wrapper for a received TCP payload with a capture timestamp. */ 4 | public final class TimestampedByteVector { 5 | public final long timestampNs; 6 | public final byte[] data; 7 | public TimestampedByteVector(long timestampNs, byte[] data) { 8 | this.timestampNs = timestampNs; 9 | this.data = data; 10 | } 11 | public double getTimestampSeconds() { return timestampNs / 1_000_000_000.0; } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IWantToQuit.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import io.singularitynet.projectmalmo.MissionInit; 4 | 5 | public interface IWantToQuit { 6 | public void cleanup(); 7 | 8 | boolean doIWantToQuit(MissionInit currentMissionInit); 9 | 10 | String getOutcome(); 11 | 12 | /** Called once AFTER buildOnWorld but before the mission starts - use for any necessary mission initialisation. 13 | */ 14 | public void prepare(MissionInit missionInit); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/LevelStorageMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.world.level.storage.LevelStorage; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Mutable; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import java.nio.file.Path; 9 | 10 | @Mixin(LevelStorage.class) 11 | public interface LevelStorageMixin { 12 | @Accessor("savesDirectory") @Mutable 13 | public void setSavesDirectory(Path path); 14 | 15 | @Accessor("backupsDirectory") @Mutable 16 | public void setBackupsDirectory(Path path); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_tex_color.vsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 Position; 4 | in vec4 Color; 5 | in vec2 UV0; 6 | // Accept overlays/light/normal even if unused, to match common entity/chunk formats 7 | in vec2 UV1; 8 | in vec2 UV2; 9 | in vec3 Normal; 10 | 11 | uniform mat4 ModelViewMat; 12 | uniform mat4 ProjMat; 13 | uniform vec3 ChunkOffset; 14 | 15 | out vec2 texCoord0; 16 | out vec4 vertexColor; 17 | 18 | void main() { 19 | vec3 worldPos = Position + ChunkOffset; 20 | gl_Position = ProjMat * ModelViewMat * vec4(worldPos, 1.0); 21 | texCoord0 = UV0; 22 | vertexColor = Color; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/LootTableProviderMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.data.server.loottable.LootTableProvider; 4 | import net.minecraft.util.Identifier; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | @Mixin(LootTableProvider.class) 12 | public interface LootTableProviderMixin { 13 | @Accessor("lootTableIds") 14 | Set getlootTableIds(); 15 | 16 | @Accessor("lootTypeGenerators") 17 | List getlootTypeGenerators(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.client.Keyboard; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.Mouse; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Mutable; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | 11 | @Mixin(MinecraftClient.class) 12 | public interface MinecraftClientMixin { 13 | @Accessor("keyboard") @Mutable 14 | public void setKeyboard(Keyboard keyboard); 15 | 16 | @Accessor("mouse") @Mutable 17 | public void setMouse(Mouse keyboard); 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/TitleScreenEvents.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import net.fabricmc.fabric.api.event.Event; 4 | import net.fabricmc.fabric.api.event.EventFactory; 5 | 6 | 7 | public class TitleScreenEvents { 8 | public static final Event END_TITLESCREEN_INIT= EventFactory.createArrayBacked(TitleScreenEvents.EndInit.class, 9 | (callbacks) -> () -> { 10 | 11 | for (TitleScreenEvents.EndInit event : callbacks) { 12 | event.onTitleScreenEndInit(); 13 | } 14 | }); 15 | 16 | @FunctionalInterface 17 | public interface EndInit { 18 | void onTitleScreenEndInit(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/ServerPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | import net.minecraft.server.network.ServerPlayNetworkHandler; 10 | 11 | 12 | @Mixin(ServerPlayNetworkHandler.class) 13 | public class ServerPlayNetworkHandlerMixin { 14 | @Inject(method="checkForSpam", at = @At("HEAD"), cancellable = true) 15 | private void checkForSpam(CallbackInfo ci) { 16 | ci.cancel(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/utils/ScreenHelper.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.utils; 2 | 3 | public class ScreenHelper implements IScreenHelper { 4 | 5 | public enum TextCategory 6 | { 7 | TXT_INFO, 8 | TXT_SERVER_STATE, 9 | TXT_CLIENT_STATE, 10 | TXT_SERVER_WARNING, 11 | TXT_CLIENT_WARNING, 12 | TXT_AGENT_MESSAGE 13 | } 14 | 15 | @Override 16 | public void clearFragment(String infoReserveStatus) { 17 | // TODO Auto-generated method stub 18 | 19 | } 20 | 21 | @Override 22 | public void addFragment(String text, TextCategory category, String handle) { 23 | 24 | } 25 | 26 | @Override 27 | public void addFragment(String text, TextCategory category, int handle) { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/MinecraftSegmentationIT.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assumptions.assumeTrue; 6 | 7 | /** 8 | * JUnit wrapper to run the integration harness when RUN_SEG_TEST=1 is set. 9 | * Prefer using: gradlew runSegTest 10 | */ 11 | public class MinecraftSegmentationIT { 12 | @Test 13 | void launchesAndReceivesSegmentationFrames() throws Exception { 14 | assumeTrue("1".equals(System.getenv().getOrDefault("RUN_SEG_TEST", "0")), 15 | "Set RUN_SEG_TEST=1 to run this integration test."); 16 | MinecraftSegmentationTestMain.main(new String[]{ System.getProperty("mission", "src/test/resources/mission.xml") }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/events/ScreenEvents.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.events; 2 | 3 | import net.fabricmc.fabric.api.event.Event; 4 | import net.fabricmc.fabric.api.event.EventFactory; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.gui.screen.Screen; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | public interface ScreenEvents { 10 | // event for setScreen 11 | Event SET_SCREEN = EventFactory.createArrayBacked(ScreenEvents.class, callbacks -> (MinecraftClient client, @Nullable Screen screen) -> { 12 | for (ScreenEvents callback : callbacks) { 13 | callback.interact(client, screen); 14 | } 15 | }); 16 | 17 | void interact(MinecraftClient client, @Nullable Screen screen); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/Server/ServerState.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.Server; 2 | 3 | 4 | import io.singularitynet.IState; 5 | 6 | /** Set of states used by MissionStateTracker to ensure the Mod remains in a valid state.
7 | * Note: these do not necessarily occur in the order presented here. 8 | * If adding states here, please also add a MissionStateEpisode class to MissionStateTracker, 9 | * and a line to the switch statement in MissionStateTracker.getStateEpisodeForState(). 10 | */ 11 | public enum ServerState implements IState 12 | { 13 | WAITING_FOR_MOD_READY, 14 | DORMANT, 15 | BUILDING_WORLD, 16 | WAITING_FOR_AGENTS_TO_ASSEMBLE, 17 | RUNNING, 18 | MISSION_ENDED, 19 | MISSION_ABORTED, 20 | WAITING_FOR_AGENTS_TO_QUIT, 21 | ERROR, 22 | CLEAN_UP 23 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/ICommandHandler.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import io.singularitynet.projectmalmo.MissionInit; 4 | 5 | public interface ICommandHandler { 6 | 7 | 8 | /** 9 | * @return true if this object is overriding the default Minecraft control method. 10 | */ 11 | public boolean isOverriding(); 12 | 13 | /** Switch this command handler on/off. If on, it will be overriding the default Minecraft control method. 14 | * @param b set this control on/off. 15 | */ 16 | public void setOverriding(boolean b); 17 | 18 | void install(MissionInit currentMissionInit); 19 | 20 | void deinstall(MissionInit currentMissionInit); 21 | 22 | boolean execute(String command, MissionInit currentMissionInit); 23 | } 24 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | "%d{HH:mm:ss.SSS} %-5p %m%n" 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/EventWrapper.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import net.fabricmc.fabric.api.event.Event; 4 | 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | class EventWrapper { 11 | private Map> registry = null; 12 | private static EventWrapper instance = new EventWrapper(); 13 | 14 | private EventWrapper(){ 15 | registry = new HashMap<>(); 16 | }; 17 | 18 | public static EventWrapper getInstance(){ 19 | return instance; 20 | } 21 | 22 | public void register(Event event, T invoker) { 23 | registry.getOrDefault(event, new HashSet()).add(invoker); 24 | } 25 | 26 | public void unregister(Event event, T in) { 27 | registry.get(event).remove(in); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_tex.vsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 Position; 4 | in vec2 UV0; 5 | // Some vertex formats (entities, chunk meshes) include additional attributes 6 | // like overlay UV1/light UV2/Normal that our shader does not use. Declare them 7 | // optionally so the program can link against those formats without falling back 8 | // to a mismatched simpler format that would scramble attributes. 9 | in vec2 UV1; 10 | in vec2 UV2; 11 | in vec3 Normal; 12 | 13 | uniform mat4 ModelViewMat; 14 | uniform mat4 ProjMat; 15 | uniform vec3 ChunkOffset; 16 | 17 | out vec2 texCoord0; 18 | out vec4 vertexColor; 19 | 20 | void main() { 21 | vec3 worldPos = Position + ChunkOffset; 22 | gl_Position = ProjMat * ModelViewMat * vec4(worldPos, 1.0); 23 | texCoord0 = UV0; 24 | vertexColor = vec4(1.0); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MobEntityAccessorMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.entity.ai.control.JumpControl; 4 | import net.minecraft.entity.ai.control.MoveControl; 5 | import net.minecraft.entity.mob.MobEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Mutable; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | @Mixin(MobEntity.class) 11 | public interface MobEntityAccessorMixin { 12 | 13 | @Accessor("moveControl") 14 | public MoveControl getMoveControl(); 15 | 16 | @Accessor("moveControl") @Mutable 17 | public void setMoveControl(MoveControl control); 18 | 19 | @Accessor("jumpControl") 20 | public JumpControl getJumpControl(); 21 | 22 | @Accessor("jumpControl") @Mutable 23 | public void setJumpControl(JumpControl control); 24 | } 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![CI](https://github.com/trueagi-io/Vereya/actions/workflows/build.yml/badge.svg) 2 | 3 | ## Overview 4 | 5 | Vereya provides API for controlling AI agents in Minecraft. This mod inherits some pieces of the Malmo project, but with various changes and additions. 6 | Vereya should work with Minecraft 1.21 7 | 8 | ## building and installation 9 | 10 | *set pauseOnLostFocus:false* in options.txt 11 | 12 | run in project directory 13 | 14 | `./gradlew build` 15 | 16 | copy mod in mods directory: 17 | 18 | `cp ./build/libs/vereya-*.jar ~/.minecraft/mods/` 19 | 20 | now install python library: 21 | 22 | pip install git+https://github.com/trueagi-io/minecraft-demo.git 23 | 24 | Vereya requires fabric loader and fabric api to installed. Please see instructions 25 | 26 | https://fabricmc.net/use/installer/ 27 | 28 | https://www.curseforge.com/minecraft/mc-mods/fabric-api 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/GlUniformChunkOffsetMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.gl.GlUniform; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(GlUniform.class) 12 | public abstract class GlUniformChunkOffsetMixin { 13 | 14 | @Shadow private String name; 15 | 16 | @Inject(method = "set(FFF)V", at = @At("HEAD")) 17 | private void vereya$captureChunkOffset(float x, float y, float z, CallbackInfo ci) { 18 | if ("ChunkOffset".equals(this.name)) { 19 | TextureHelper.updateChunkOffset(x, y, z); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MinecraftClientEventsMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.events.ScreenEvents; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gui.screen.Screen; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(MinecraftClient.class) 13 | public class MinecraftClientEventsMixin { 14 | @Inject(at = @At("HEAD"), method = "setScreen(Lnet/minecraft/client/gui/screen/Screen;)V") 15 | private void setScreen(@Nullable Screen screen, CallbackInfo info) { 16 | ScreenEvents.SET_SCREEN.invoker().interact((MinecraftClient) (Object) this, screen); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/GlStateManagerBindTextureMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.platform.GlStateManager; 4 | import io.singularitynet.utils.TextureHelper; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | /** 11 | * Hooks low-level texture binding so that any call to GlStateManager._bindTexture 12 | * (eg from AbstractTexture.bindTexture) participates in segmentation logging and 13 | * colour selection via TextureHelper. 14 | */ 15 | @Mixin(GlStateManager.class) 16 | public abstract class GlStateManagerBindTextureMixin { 17 | 18 | @Inject(method = "_bindTexture(I)V", at = @At("HEAD")) 19 | private static void vereya$onBindTexture(int glId, CallbackInfo ci) { 20 | TextureHelper.onTextureBoundGlId(glId); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "vereya", 4 | "version": "${version}", 5 | 6 | "name": "Vereya project", 7 | "description": "This is an example description! Tell everyone what your mod is about!", 8 | "authors": [ 9 | "Anatoly Belikov" 10 | ], 11 | "contact": { 12 | "homepage": "https://github.com/trueagi-io/Vereya", 13 | "sources": "https://github.com/trueagi-io/Vereya" 14 | }, 15 | 16 | "license": "CC0-1.0", 17 | "icon": "assets/modid/icon.png", 18 | 19 | "environment": "*", 20 | "entrypoints": { 21 | "client": [ "io.singularitynet.Client.VereyaModClient" ], 22 | "main": [ "io.singularitynet.Server.VereyaModServer" ] 23 | }, 24 | "mixins": [ 25 | "vereya.mixins.json" 26 | ], 27 | 28 | "depends": { 29 | "fabricloader": ">=0.15.11", 30 | "fabric": "*", 31 | "minecraft": "~1.21", 32 | "java": ">=21" 33 | }, 34 | "suggests": { 35 | "another-mod": "*" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/StringServer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.concurrent.atomic.AtomicReference; 5 | import java.util.function.Consumer; 6 | 7 | /** Server that decodes each packet as UTF-8 string and forwards to a handler. */ 8 | public final class StringServer { 9 | private final int port; 10 | private final Consumer handleString; 11 | private final TCPServer tcp; 12 | private Thread thread; 13 | 14 | public StringServer(int port, Consumer handleString) { 15 | this.port = port; 16 | this.handleString = handleString; 17 | this.tcp = new TCPServer(port, (tv) -> { 18 | String s = new String(tv.data, StandardCharsets.UTF_8); 19 | handleString.accept(s); 20 | }); 21 | } 22 | 23 | public Thread start() { this.thread = tcp.start("StringServer-" + port); return this.thread; } 24 | public void stop() { tcp.stop(); } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/RenderSystemTextureGlMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import io.singularitynet.utils.TextureHelper; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | /** 11 | * Hooks the integer-overload of RenderSystem.setShaderTexture so that binds 12 | * which only specify a GL id (rather than an Identifier) are still visible to 13 | * the segmentation logging and colour selection logic. 14 | */ 15 | @Mixin(RenderSystem.class) 16 | public abstract class RenderSystemTextureGlMixin { 17 | 18 | @Inject( 19 | method = "setShaderTexture(II)V", 20 | at = @At("HEAD") 21 | ) 22 | private static void vereya$onSetShaderTextureGl(int unit, int glId, CallbackInfo ci) { 23 | TextureHelper.onTextureBoundGlId(glId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/TitleScreenMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.TitleScreenEvents; 4 | import net.minecraft.client.gui.screen.TitleScreen; 5 | import net.minecraft.client.gui.screen.SplashTextRenderer; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(TitleScreen.class) 14 | public class TitleScreenMixin { 15 | @Shadow @Nullable private SplashTextRenderer splashText; 16 | 17 | @Inject(at = @At("TAIL"), method = "init()V") 18 | private void init(CallbackInfo info) { 19 | if(this.splashText != null) { 20 | TitleScreenEvents.END_TITLESCREEN_INIT.invoker().onTitleScreenEndInit(); 21 | System.out.println("This line is printed by an example mod mixin!"); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/EntityRenderDispatcherAccessor.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.client.render.VertexConsumerProvider; 4 | import net.minecraft.client.render.entity.EntityRenderDispatcher; 5 | import net.minecraft.client.util.math.MatrixStack; 6 | import net.minecraft.entity.Entity; 7 | import net.minecraft.world.WorldView; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.gen.Invoker; 10 | 11 | @Mixin(EntityRenderDispatcher.class) 12 | public interface EntityRenderDispatcherAccessor { 13 | @Invoker("renderShadow") 14 | static void invokeRenderShadow(MatrixStack matrices, 15 | VertexConsumerProvider vertexConsumers, 16 | Entity entity, 17 | float opacity, 18 | float tickDelta, 19 | WorldView world, 20 | float radius) { 21 | throw new AssertionError(); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/ServerWorldMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.events.ServerEntityEventsVereya; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.util.ActionResult; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | 12 | @Mixin(ServerWorld.class) 13 | class ServerWorldMixin { 14 | 15 | @Inject(method = "Lnet/minecraft/server/world/ServerWorld;addEntity(Lnet/minecraft/entity/Entity;)Z", at = @At("HEAD"), cancellable = true) 16 | void invokeEntityAddEvent(Entity entity, CallbackInfoReturnable cir) { 17 | ActionResult result = ServerEntityEventsVereya.BEFORE_ENTITY_ADD.invoker().interact(entity, (ServerWorld)(Object)this); 18 | if (result == ActionResult.FAIL) { 19 | cir.cancel(); 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/RenderSystemTextureMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import io.singularitynet.utils.TextureHelper; 5 | import net.minecraft.util.Identifier; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | /** 12 | * Hooks RenderSystem.setShaderTexture so that segmentation logging and 13 | * colour selection see all textures bound via render phases, not just 14 | * those routed through TextureManager.bindTextureInner. 15 | */ 16 | @Mixin(RenderSystem.class) 17 | public abstract class RenderSystemTextureMixin { 18 | 19 | @Inject( 20 | method = "setShaderTexture(ILnet/minecraft/util/Identifier;)V", 21 | at = @At("HEAD") 22 | ) 23 | private static void vereya$onSetShaderTexture(int unit, Identifier id, CallbackInfo ci) { 24 | TextureHelper.onTextureBound(id); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": "annotate_position", 3 | "fragment": "annotate", 4 | "samplers": [ 5 | { "name": "Sampler0" } 6 | ], 7 | "uniforms": [ 8 | { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 9 | { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 10 | { "name": "ChunkOffset", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, 11 | { "name": "entityColourR", "type": "int", "count": 1, "values": [255] }, 12 | { "name": "entityColourG", "type": "int", "count": 1, "values": [255] }, 13 | { "name": "entityColourB", "type": "int", "count": 1, "values": [255] }, 14 | { "name": "debugMode", "type": "int", "count": 1, "values": [0] }, 15 | { "name": "atlasGrid", "type": "int", "count": 1, "values": [32] }, 16 | { "name": "atlasLod", "type": "int", "count": 1, "values": [8] }, 17 | { "name": "respectAlpha", "type": "int", "count": 1, "values": [0] } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/VideoServer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** Server that parses incoming packets into TimestampedVideoFrame and forwards to handler. */ 6 | public final class VideoServer { 7 | private final int port; 8 | private final int channels; 9 | private final FrameType frametype; 10 | private final Consumer handleFrame; 11 | private final TCPServer tcp; 12 | private Thread thread; 13 | 14 | public VideoServer(int port, int channels, FrameType frametype, Consumer handleFrame) { 15 | this.port = port; 16 | this.channels = channels; 17 | this.frametype = frametype; 18 | this.handleFrame = handleFrame; 19 | this.tcp = new TCPServer(port, (tv) -> { 20 | TimestampedVideoFrame frame = new TimestampedVideoFrame(tv, frametype); 21 | handleFrame.accept(frame); 22 | }); 23 | } 24 | 25 | public Thread start() { this.thread = tcp.start("VideoServer-" + port + "-" + frametype); return this.thread; } 26 | public void stop() { tcp.stop(); } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_tex.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": "annotate_position_tex", 3 | "fragment": "annotate", 4 | "samplers": [ 5 | { "name": "Sampler0" } 6 | ], 7 | "uniforms": [ 8 | { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 9 | { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 10 | { "name": "ChunkOffset", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, 11 | { "name": "entityColourR", "type": "int", "count": 1, "values": [255] }, 12 | { "name": "entityColourG", "type": "int", "count": 1, "values": [255] }, 13 | { "name": "entityColourB", "type": "int", "count": 1, "values": [255] }, 14 | { "name": "debugMode", "type": "int", "count": 1, "values": [0] }, 15 | { "name": "atlasGrid", "type": "int", "count": 1, "values": [32] }, 16 | { "name": "atlasLod", "type": "int", "count": 1, "values": [8] }, 17 | { "name": "respectAlpha", "type": "int", "count": 1, "values": [0] } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_color.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": "annotate_position_color", 3 | "fragment": "annotate", 4 | "samplers": [ 5 | { "name": "Sampler0" } 6 | ], 7 | "uniforms": [ 8 | { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 9 | { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 10 | { "name": "ChunkOffset", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, 11 | { "name": "entityColourR", "type": "int", "count": 1, "values": [255] }, 12 | { "name": "entityColourG", "type": "int", "count": 1, "values": [255] }, 13 | { "name": "entityColourB", "type": "int", "count": 1, "values": [255] }, 14 | { "name": "debugMode", "type": "int", "count": 1, "values": [0] }, 15 | { "name": "atlasGrid", "type": "int", "count": 1, "values": [32] }, 16 | { "name": "atlasLod", "type": "int", "count": 1, "values": [8] }, 17 | { "name": "respectAlpha", "type": "int", "count": 1, "values": [0] } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate_position_tex_color.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": "annotate_position_tex_color", 3 | "fragment": "annotate", 4 | "samplers": [ 5 | { "name": "Sampler0" } 6 | ], 7 | "uniforms": [ 8 | { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 9 | { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] }, 10 | { "name": "ChunkOffset", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, 11 | { "name": "entityColourR", "type": "int", "count": 1, "values": [255] }, 12 | { "name": "entityColourG", "type": "int", "count": 1, "values": [255] }, 13 | { "name": "entityColourB", "type": "int", "count": 1, "values": [255] }, 14 | { "name": "debugMode", "type": "int", "count": 1, "values": [0] }, 15 | { "name": "atlasGrid", "type": "int", "count": 1, "values": [32] }, 16 | { "name": "atlasLod", "type": "int", "count": 1, "values": [8] }, 17 | { "name": "respectAlpha", "type": "int", "count": 1, "values": [0] } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MyChatHud.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.ClientChatListener; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gui.hud.ChatHud; 6 | import net.minecraft.client.gui.hud.MessageIndicator; 7 | import net.minecraft.network.message.MessageSignatureData; 8 | import net.minecraft.text.Text; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class MyChatHud extends ChatHud { 15 | 16 | private List listeners; 17 | 18 | public MyChatHud(MinecraftClient client) { 19 | super(client); 20 | this.listeners = new ArrayList<>(); 21 | } 22 | 23 | public void addMessage(Text message, @Nullable MessageSignatureData signature, @Nullable MessageIndicator indicator) { 24 | super.addMessage(message, signature, indicator); 25 | for (ClientChatListener listener: listeners) { 26 | listener.onChatMessage(message); 27 | } 28 | } 29 | 30 | public List getListeners(){ 31 | return this.listeners; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MessagePayload.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | import net.minecraft.network.PacketByteBuf; 4 | import net.minecraft.network.RegistryByteBuf; 5 | import net.minecraft.network.codec.PacketCodec; 6 | import net.minecraft.network.packet.CustomPayload; 7 | 8 | public record MessagePayload(VereyaMessage msg) implements CustomPayload { 9 | public static final PacketCodec PACKET_CODEC = new PacketCodec() { 10 | 11 | public VereyaMessage decode(PacketByteBuf byteBuf) { 12 | final VereyaMessage message = new VereyaMessage(); 13 | message.fromBytes(byteBuf); 14 | return message; 15 | } 16 | 17 | public void encode(PacketByteBuf buf, VereyaMessage message) { 18 | message.toBytes(buf); 19 | } 20 | }; 21 | 22 | public static final CustomPayload.Id ID = new CustomPayload.Id<>(NetworkConstants.CLIENT2SERVER); 23 | public static final PacketCodec CODEC = PacketCodec.tuple(PACKET_CODEC, MessagePayload::msg, MessagePayload::new); 24 | 25 | @Override 26 | public CustomPayload.Id getId() { 27 | return ID; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/ServerWorldEntityLoaderMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.events.ServerEntityEventsVereya; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.util.ActionResult; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(targets = "net/minecraft/server/world/ServerWorld$ServerEntityHandler") 15 | abstract class ServerWorldEntityLoaderMixin { 16 | // final synthetic Lnet/minecraft/server/world/ServerWorld; field_26936 17 | @SuppressWarnings("ShadowTarget") 18 | @Shadow 19 | @Final 20 | private ServerWorld field_26936; 21 | 22 | @Inject(method = "startTracking(Lnet/minecraft/entity/Entity;)V", at = @At("HEAD"), cancellable = true) 23 | private void invokeEntityLoadEvent(Entity entity, CallbackInfo ci) { 24 | ActionResult result = ServerEntityEventsVereya.BEFORE_ENTITY_LOAD.invoker().interact(entity, this.field_26936); 25 | if (result == ActionResult.FAIL) { 26 | ci.cancel(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/EntityMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | 4 | import net.minecraft.entity.mob.MobEntity; 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | import net.minecraft.entity.Entity; 12 | 13 | @Mixin(Entity.class) 14 | public class EntityMixin { 15 | 16 | private static final Logger LOGGER = LogManager.getLogger(EntityMixin.class); 17 | 18 | @Inject(method="remove", at=@At("HEAD"), cancellable = true) 19 | public void remove(Entity.RemovalReason reason, CallbackInfo c) { 20 | if ((Object) this instanceof MobEntity) { 21 | MobEntity mob = (MobEntity) (Object) this; 22 | if(mob.isAiDisabled()){ 23 | if(reason == Entity.RemovalReason.DISCARDED){ 24 | mob.setDespawnCounter(0); 25 | c.cancel(); 26 | LOGGER.trace("cancelled removal of entity " + mob.getUuidAsString()); 27 | } else { 28 | LOGGER.trace("removed entity " + mob.getUuidAsString()); 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/DiscreteMovementCommandsImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 4 | import io.singularitynet.projectmalmo.DiscreteMovementCommands; 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | 8 | public class DiscreteMovementCommandsImplementation extends CommandGroup implements ICommandHandler { 9 | 10 | private static final Logger LOGGER = LogManager.getLogger(DiscreteMovementCommandsImplementation.class.getName()); 11 | 12 | public DiscreteMovementCommandsImplementation(){ 13 | setShareParametersWithChildren(true); // Pass our parameter block on to the following children: 14 | this.addCommandHandler(new CommandForAttackAndUseImplementation()); 15 | this.addCommandHandler(new CommandForDiscreteRobotNavigationImplementation()); 16 | } 17 | 18 | @Override 19 | public boolean parseParameters(Object params) 20 | { 21 | super.parseParameters(params); 22 | 23 | if (params == null || !(params instanceof DiscreteMovementCommands)) 24 | return false; 25 | 26 | DiscreteMovementCommands dmparams = (DiscreteMovementCommands)params; 27 | setUpAllowAndDenyLists(dmparams.getModifierList()); 28 | return true; 29 | } 30 | 31 | @Override 32 | public boolean isFixed() { return true; } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/WorldRendererSkyMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.render.Camera; 5 | import net.minecraft.client.render.WorldRenderer; 6 | import org.joml.Matrix4f; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | /** 13 | * Suppresses the regular sky draw during the segmentation pass; the 14 | * segmentation framebuffer is pre-filled with the mission sky colour. 15 | */ 16 | @Mixin(WorldRenderer.class) 17 | public abstract class WorldRendererSkyMixin { 18 | 19 | @Inject(method = "renderSky(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;FLnet/minecraft/client/render/Camera;ZLjava/lang/Runnable;)V", at = @At("HEAD"), cancellable = true) 20 | private void vereya$skipSky(Matrix4f matrix4f, 21 | Matrix4f projectionMatrix, 22 | float tickDelta, 23 | Camera camera, 24 | boolean thickFog, 25 | Runnable fogCallback, 26 | CallbackInfo ci) { 27 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 28 | ci.cancel(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MinecraftClientFramebufferMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gl.Framebuffer; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | /** 12 | * Ensures the segmentation render pass targets the off-screen segmentation 13 | * framebuffer instead of the on-screen framebuffer. Without this, parts of the 14 | * render pipeline that explicitly re-bind the main framebuffer during a world 15 | * render (e.g., post-processing or weather layers) would override our manual 16 | * FBO binding and draw the segmentation colours into the visible game window. 17 | */ 18 | @Mixin(MinecraftClient.class) 19 | public abstract class MinecraftClientFramebufferMixin { 20 | 21 | @Inject(method = "getFramebuffer", at = @At("HEAD"), cancellable = true) 22 | private void vereya$returnSegmentationFboWhenActive(CallbackInfoReturnable cir) { 23 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 24 | Framebuffer seg = TextureHelper.getSegmentationFramebuffer(); 25 | if (seg != null) { 26 | cir.setReturnValue(seg); 27 | } 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/TextureManagerMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.texture.AbstractTexture; 5 | import net.minecraft.client.texture.TextureManager; 6 | import net.minecraft.util.Identifier; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(TextureManager.class) 13 | public abstract class TextureManagerMixin { 14 | 15 | @Inject(method = "bindTextureInner", at = @At("TAIL")) 16 | private void vereya$afterBind(Identifier id, CallbackInfo ci) { 17 | TextureHelper.onTextureBound(id); 18 | } 19 | 20 | /** 21 | * After a texture is registered and has a GL id, record the mapping so we 22 | * can later recover the Identifier when only the integer id is available. 23 | */ 24 | @Inject(method = "registerTexture", at = @At("TAIL")) 25 | private void vereya$afterRegisterTexture(Identifier id, AbstractTexture texture, CallbackInfo ci) { 26 | if (id == null || texture == null) return; 27 | try { 28 | int glId = texture.getGlId(); 29 | TextureHelper.registerTextureGlId(id, glId); 30 | } catch (Throwable t) { 31 | // Best-effort; missing ids will simply appear as unmapped in logs. 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MouseMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | 4 | import io.singularitynet.Client.VereyaModClient; 5 | import net.minecraft.client.Mouse; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(Mouse.class) 12 | public class MouseMixin { 13 | @Inject(method="onMouseButton", at = @At("HEAD")) 14 | private void onOnMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { 15 | if(VereyaModClient.MyMouse.class.isInstance(this)){ 16 | VereyaModClient.MyMouse myMouse = ((VereyaModClient.MyMouse)((Object)this)); 17 | myMouse.onMouseUsed(); 18 | } 19 | } 20 | 21 | /** 22 | * Cancellable injection, note that we set the "cancellable" 23 | * flag to "true" in the injector annotation 24 | */ 25 | @Inject(method = "onCursorPos", at = @At("HEAD"), cancellable = true) 26 | private void onOnCursorPos(long window, double x, double y, CallbackInfo ci) { 27 | if(VereyaModClient.MyMouse.class.isInstance(this)){ 28 | VereyaModClient.MyMouse myMouse = ((VereyaModClient.MyMouse)((Object)this)); 29 | myMouse.onMouseUsed(); 30 | boolean result = myMouse.shouldUpdate(); 31 | if (result) 32 | return; 33 | ci.cancel(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/WorldRendererShaderMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import io.singularitynet.utils.TextureHelper; 5 | import net.minecraft.client.gl.ShaderProgram; 6 | import net.minecraft.client.render.WorldRenderer; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | 11 | import java.util.function.Supplier; 12 | 13 | /** 14 | * During the segmentation pass, force Minecraft to use our annotate shader 15 | * programs in place of the normal rendertypes by redirecting calls to 16 | * RenderSystem.setShader. Outside the seg pass the normal supplier is used. 17 | */ 18 | @Mixin(WorldRenderer.class) 19 | public abstract class WorldRendererShaderMixin { 20 | 21 | @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShader(Ljava/util/function/Supplier;)V")) 22 | private void vereya$swapShaderForSegmentation(Supplier supplier) { 23 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 24 | ShaderProgram orig = supplier.get(); 25 | ShaderProgram annotate = TextureHelper.getAnnotateProgramForFormat(orig.getFormat()); 26 | // Apply any pending colour/uniforms to the annotate program 27 | TextureHelper.applyPendingColourToProgram(annotate); 28 | RenderSystem.setShader(() -> annotate); 29 | } else { 30 | RenderSystem.setShader(supplier); 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/IState.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // --------------------------------------------------------------------------------------------------import net.minecraft.client.Minecraft; 19 | 20 | package io.singularitynet; 21 | 22 | /** Simple interface for a representation of a state.
23 | * Used by ClientMissionState and ServerMissionState. 24 | */ 25 | public interface IState 26 | { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/resources/vereya.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "io.singularitynet.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [], 7 | "client": [ 8 | "TitleScreenMixin", 9 | "SessionMixin", 10 | "MinecraftClientMixin", 11 | "GameOptionsMixin", 12 | "KeyBindingMixin", 13 | "MouseMixin", 14 | "MouseAccessorMixin", 15 | "InGameHudMixin", 16 | "LevelStorageMixin", 17 | "MinecraftClientEventsMixin", 18 | "LootTableProviderMixin", 19 | "MobEntityMixin", 20 | "MobEntityAccessorMixin", 21 | "ClientWorldMixinAccess", 22 | "EntityMixin", 23 | "ServerEntityManagerMixin", 24 | "ServerWorldMixin", 25 | "ServerWorldEntityLoaderMixin", 26 | "ServerPlayNetworkHandlerMixin", 27 | "WorldRendererColourmapMixin", 28 | "WorldRendererSkyMixin", 29 | "TextureManagerMixin", 30 | "RenderSystemTextureMixin", 31 | "RenderSystemTextureGlMixin", 32 | "VertexBufferMixin", 33 | "GlUniformChunkOffsetMixin", 34 | "RenderSystemDrawMixin", 35 | "RenderSystemShaderSwapMixin", 36 | "GlStateManagerBindTextureMixin", 37 | "GlStateManagerDrawMixin", 38 | "WorldRendererShaderMixin", 39 | "BlockRenderManagerMixin", 40 | "EntityRenderDispatcherMixin", 41 | "EntityRendererMixin", 42 | "EntityRenderDispatcherShadowMixin", 43 | "EntityRenderDispatcherAccessor", 44 | "MinecraftClientFramebufferMixin" 45 | ], 46 | "server": [ 47 | "ServerEntityManagerMixin", 48 | "ServerWorldMixin", 49 | "ServerWorldEntityLoaderMixin", 50 | "ServerPlayNetworkHandlerMixin" 51 | ], 52 | "injectors": { 53 | "defaultRequire": 1 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/HandlerBase.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | 6 | /** Lightweight baseclass for all handlers - provides access to parameters from the XML file. 7 | */ 8 | public class HandlerBase 9 | { 10 | /** A static list of all classes that implement a handler - used to aid dynamic handler creation. 11 | */ 12 | static ArrayList handlers; 13 | 14 | /** Pointer up to the MissionBehaviour object that created us - useful for certain mission handlers. 15 | */ 16 | private MissionBehaviour parentBehaviour = null; 17 | 18 | public HandlerBase() {} 19 | 20 | public void setParentBehaviour(MissionBehaviour mb) 21 | { 22 | this.parentBehaviour = mb; 23 | } 24 | 25 | protected MissionBehaviour parentBehaviour() 26 | { 27 | return this.parentBehaviour; 28 | } 29 | 30 | /** Attempt to parse the given object as a set of parameters for this handler. 31 | * @param params the parameter block to parse 32 | * @return true if the object made sense for this handler; false otherwise. 33 | */ 34 | public boolean parseParameters(Object params) 35 | { 36 | return true; 37 | } 38 | 39 | /** Our chance to add any info the server might need before the mission starts. 40 | * @param map Map of data sent to server in the client's ping message. 41 | */ 42 | public void appendExtraServerInformation(HashMap map) 43 | { 44 | // Mostly does nothing, but, for example, TurnBasedCommandsImplementation uses this 45 | // in order to register with the server. 46 | } 47 | } -------------------------------------------------------------------------------- /server/server.properties: -------------------------------------------------------------------------------- 1 | #Minecraft server properties 2 | #Tue Oct 29 19:57:45 MSK 2024 3 | accepts-transfers=false 4 | allow-flight=false 5 | allow-nether=true 6 | broadcast-console-to-ops=true 7 | broadcast-rcon-to-ops=true 8 | bug-report-link= 9 | difficulty=easy 10 | enable-command-block=false 11 | enable-jmx-monitoring=false 12 | enable-query=false 13 | enable-rcon=false 14 | enable-status=true 15 | enforce-secure-profile=false 16 | enforce-whitelist=false 17 | entity-broadcast-range-percentage=100 18 | force-gamemode=false 19 | function-permission-level=2 20 | gamemode=survival 21 | generate-structures=true 22 | generator-settings={"biome"\:"minecraft\:desert","layers"\:[{"block"\:"minecraft\:bedrock","height"\:1},{"block"\:"minecraft\:stone","height"\:3},{"block"\:"minecraft\:sandstone","height"\:116}],"structures"\:{"village"\:{}}} 23 | hardcore=false 24 | hide-online-players=false 25 | initial-disabled-packs= 26 | initial-enabled-packs=vanilla 27 | level-name=world 28 | level-seed=43839877843298 29 | level-type=minecraft\:normal 30 | log-ips=true 31 | max-chained-neighbor-updates=1000000 32 | max-players=20 33 | max-tick-time=60000 34 | max-world-size=29999984 35 | motd=A Minecraft Server 36 | network-compression-threshold=256 37 | online-mode=false 38 | op-permission-level=4 39 | player-idle-timeout=0 40 | prevent-proxy-connections=false 41 | pvp=true 42 | query.port=25565 43 | rate-limit=0 44 | rcon.password= 45 | rcon.port=25575 46 | region-file-compression=deflate 47 | require-resource-pack=false 48 | resource-pack= 49 | resource-pack-id= 50 | resource-pack-prompt= 51 | resource-pack-sha1= 52 | server-ip= 53 | server-port=25565 54 | simulation-distance=10 55 | spawn-animals=true 56 | spawn-monsters=true 57 | spawn-npcs=true 58 | spawn-protection=16 59 | sync-chunk-writes=true 60 | text-filtering-config= 61 | use-native-transport=true 62 | view-distance=10 63 | white-list=false 64 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/VereyaMessageType.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet; 2 | 3 | public enum VereyaMessageType 4 | { 5 | SERVER_NULLMESSASGE, 6 | SERVER_ALLPLAYERSJOINED, 7 | SERVER_GO, // All clients are running, server is running - GO! 8 | SERVER_STOPAGENTS, // Server request for all agents to stop what they are doing (mission is over) 9 | SERVER_MISSIONOVER, // Server informing that all agents have stopped, and the mission is now over. 10 | SERVER_OBSERVATIONSREADY, 11 | SERVER_TEXT, 12 | SERVER_STOPPED, 13 | SERVER_ABORT, 14 | SERVER_COLLECTITEM, 15 | SERVER_DISCARDITEM, 16 | SERVER_BUILDBATTLEREWARD, // Server has detected a reward from the build battle 17 | SERVER_SHARE_REWARD, // Server has received a reward from a client and is distributing it to the other agents 18 | SERVER_YOUR_TURN, // Server turn scheduler is telling client that it is their go next 19 | SERVER_SOMEOTHERMESSAGE, 20 | SERVER_CONTROLLED_MOB, 21 | CLIENT_AGENTREADY, // Client response to server's ready request 22 | CLIENT_AGENTRUNNING, // Client has just started running 23 | CLIENT_AGENTSTOPPED, // Client response to server's stop request 24 | CLIENT_AGENTFINISHEDMISSION,// Individual agent has finished a mission 25 | CLIENT_BAILED, // Client has hit an error and been forced to enter error state 26 | CLIENT_SHARE_REWARD, // Client has received a reward and needs to share it with other agents 27 | CLIENT_TURN_TAKEN, // Client is telling the server turn scheduler that they have just taken their turn 28 | CLIENT_SOMEOTHERMESSAGE, 29 | CLIENT_CRAFT, // Client telling the server what to craft 30 | CLIENT_INVENTORY_CHANGE, // Client tells server to modify inventory 31 | CLIENT_MISSION_INIT, // Client tells server to start a new mission 32 | CLIENT_MOVE, // move command for controlled mob 33 | SERVER_CHUNK_READY // chunk around the player was loaded 34 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/CommandForAttackAndUseImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlers; 21 | 22 | public class CommandForAttackAndUseImplementation extends CommandGroup 23 | { 24 | public CommandForAttackAndUseImplementation() 25 | { 26 | super(); 27 | setShareParametersWithChildren(true); // Pass our parameter block on to the following children: 28 | addCommandHandler(new CommandForKey("key.attack")); 29 | addCommandHandler(new CommandForKey("key.use")); 30 | } 31 | 32 | @Override 33 | public boolean isFixed() { return true; } 34 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/CommandForHotBarKeysImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | 21 | package io.singularitynet.MissionHandlers; 22 | 23 | public class CommandForHotBarKeysImplementation extends CommandGroup 24 | { 25 | public CommandForHotBarKeysImplementation() 26 | { 27 | setShareParametersWithChildren(true); // Pass our parameter block on to the following children: 28 | for (int i = 1; i <= 9; i++) 29 | { 30 | addCommandHandler(new CommandForKey("key.hotbar." + i)); 31 | } 32 | } 33 | 34 | @Override 35 | public boolean isFixed() { return true; } 36 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IWorldDecorator.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlerInterfaces; 2 | 3 | import io.singularitynet.projectmalmo.MissionInit; 4 | import net.minecraft.world.World; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public interface IWorldDecorator { 11 | 12 | /** Gives the decorator a chance to add any client-side mission handlers that might be required - eg end-points for the maze generator, etc - 13 | * and to communicate (via the map) any data back to the client-side. 14 | * @param handlers A list of handlers to which the decorator can add 15 | * @param data A map which will be passed to the client 16 | * @return true if new decorators were added 17 | */ 18 | public boolean getExtraAgentHandlersAndData(List handlers, Map data); 19 | 20 | /** Used by the turn scheduler - if the decorator wants to be part of the turn schedule, it must add a name 21 | * and a requested slot (can be null) to these arrays. 22 | * @param participants 23 | * @param participantSlots 24 | */ 25 | public void getTurnParticipants(ArrayList participants, ArrayList participantSlots); 26 | 27 | /** Used by the turn scheduler - if decorator matches this string, it must acknowledge and take its turn. 28 | * @param nextAgentName - string to match against 29 | * @return true if matching 30 | */ 31 | public boolean targetedUpdate(String nextAgentName); 32 | 33 | /** Called once AFTER buildOnWorld but before the mission starts - use for any necessary mission initialisation. 34 | */ 35 | public void prepare(MissionInit missionInit); 36 | 37 | /** Called periodically by the server, during the mission run. Use to provide dynamic behaviour. 38 | * @param world the World we are controlling. 39 | */ 40 | void update(World world); 41 | 42 | /** Called once after the mission ends - use for any necessary mission cleanup. 43 | */ 44 | public void cleanup(); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/MobEntityMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.LivingEntity; 6 | import net.minecraft.entity.ai.control.BodyControl; 7 | import net.minecraft.entity.ai.control.JumpControl; 8 | import net.minecraft.entity.ai.control.MoveControl; 9 | import net.minecraft.entity.mob.MobEntity; 10 | import net.minecraft.world.World; 11 | import org.apache.logging.log4j.LogManager; 12 | import org.apache.logging.log4j.Logger; 13 | import org.spongepowered.asm.mixin.Final; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.Shadow; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 20 | 21 | @Mixin(MobEntity.class) 22 | public abstract class MobEntityMixin extends LivingEntity { 23 | @Shadow @Final private BodyControl bodyControl; 24 | @Final 25 | private static Logger LOGGER = LogManager.getLogger(MobEntityMixin.class.getName()); 26 | 27 | @Shadow protected JumpControl jumpControl; 28 | @Shadow protected MoveControl moveControl; 29 | 30 | protected MobEntityMixin(EntityType entityType, World world) { 31 | super(entityType, world); 32 | } 33 | 34 | @Inject(method="canMoveVoluntarily", at = @At("HEAD"), cancellable = true) 35 | protected void onCanMoveVoluntarily(CallbackInfoReturnable cir){ 36 | cir.setReturnValue(!this.getWorld().isClient); 37 | } 38 | 39 | @Inject(method="tickNewAi", at = @At("HEAD"), cancellable = true) 40 | protected void tickNewAi(CallbackInfo ci){ 41 | if (this.isAiDisabled()){ 42 | this.moveControl.tick(); 43 | this.jumpControl.tick(); 44 | // there are other controls 45 | // this.bodyControl.tick(); 46 | ci.cancel(); 47 | } 48 | } 49 | 50 | @Shadow 51 | public abstract boolean isAiDisabled(); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/RewardForSendingCommandImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.IRewardProducer; 4 | import io.singularitynet.projectmalmo.MissionInit; 5 | import io.singularitynet.projectmalmo.RewardForSendingCommand; 6 | 7 | import java.math.BigDecimal; 8 | 9 | public class RewardForSendingCommandImplementation extends HandlerBase implements IRewardProducer { 10 | 11 | BigDecimal reward; 12 | String distribution; 13 | Integer dimension; 14 | boolean triggered; 15 | 16 | public RewardForSendingCommandImplementation(){ 17 | this.reward = null; 18 | this.distribution = null; 19 | this.dimension = null; 20 | this.triggered = false; 21 | } 22 | 23 | public void triggerFlag(){ 24 | this.triggered = true; 25 | } 26 | 27 | public void resetFlag(){ 28 | this.triggered = false; 29 | } 30 | 31 | public boolean isTriggered(){ 32 | return this.triggered; 33 | } 34 | 35 | @Override 36 | public boolean parseParameters(Object params){ 37 | if (params == null || !(params instanceof RewardForSendingCommand)) { 38 | return false; 39 | } 40 | RewardForSendingCommand rscparams = (RewardForSendingCommand)params; 41 | this.reward = rscparams.getReward(); 42 | this.distribution = rscparams.getDistribution(); 43 | this.dimension = rscparams.getDimension(); 44 | return true; 45 | } 46 | 47 | @Override 48 | public void cleanup() { 49 | 50 | } 51 | 52 | @Override 53 | public void prepare(MissionInit missionInit) { 54 | 55 | } 56 | 57 | @Override 58 | public void getReward(MultidimensionalReward reward) { 59 | if (this.isTriggered()){ 60 | reward.add(this.dimension, this.reward.floatValue()); 61 | this.resetFlag(); 62 | } 63 | } 64 | 65 | @Override 66 | public void trigger(Class clazz) { 67 | if (clazz.equals(CommandBase.class)){ 68 | this.triggerFlag(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/EntityRenderDispatcherMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.render.VertexConsumerProvider; 5 | import net.minecraft.client.render.entity.EntityRenderDispatcher; 6 | import net.minecraft.client.util.math.MatrixStack; 7 | import net.minecraft.entity.Entity; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(EntityRenderDispatcher.class) 14 | public abstract class EntityRenderDispatcherMixin { 15 | 16 | @Inject(method = "render(Lnet/minecraft/entity/Entity;DDDFFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 17 | at = @At("HEAD")) 18 | private void vereya$setCurrentEntity(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { 19 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 20 | TextureHelper.setCurrentEntity(entity); 21 | // Ensure a stable per-entity colour is pending before any draw calls 22 | TextureHelper.setPendingColourForEntity(entity); 23 | TextureHelper.setStrictEntityDraw(true); 24 | } 25 | } 26 | 27 | @Inject(method = "render(Lnet/minecraft/entity/Entity;DDDFFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 28 | at = @At("TAIL")) 29 | private void vereya$clearCurrentEntity(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { 30 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 31 | TextureHelper.setCurrentEntity(null); 32 | TextureHelper.setStrictEntityDraw(false); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/KeyBindingMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.MissionHandlers.CommandForKey; 4 | import net.minecraft.client.option.KeyBinding; 5 | import net.minecraft.client.util.InputUtil; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.gen.Accessor; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | import java.util.LinkedList; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | @Mixin(KeyBinding.class) 19 | public abstract class KeyBindingMixin { 20 | @Shadow public abstract String getTranslationKey(); 21 | 22 | @Inject(at = @At("TAIL"), method = "(Ljava/lang/String;Lnet/minecraft/client/util/InputUtil$Type;ILjava/lang/String;)V") 23 | private void init(String translationKey, InputUtil.Type type, int code, String category, CallbackInfo ci) { 24 | LogManager.getLogger().debug(translationKey + this.hashCode() + " KeyConstructor isInstance" + 25 | CommandForKey.KeyHook.class.isInstance(this) + " code: " + code); 26 | Map bindingMap = KeyBindingMixin.getKeyToBindings(); 27 | List keyList = new LinkedList<>(); 28 | for(Map.Entry item : bindingMap.entrySet()) { 29 | if(item.getValue().getTranslationKey().equals(this.getTranslationKey())) { 30 | LogManager.getLogger().debug("bindingMap has " + item.getKey().getCode() + ": " + item.getValue().hashCode()); 31 | keyList.add(item.getKey()); 32 | } 33 | } 34 | if(keyList.size() > 1) { 35 | LogManager.getLogger().debug("found multiple keys for the same KeyBinding" + keyList); 36 | } 37 | } 38 | 39 | @Accessor("KEY_TO_BINDINGS") 40 | public static Map getKeyToBindings() { 41 | throw new AssertionError(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/EntityRenderDispatcherShadowMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.render.VertexConsumerProvider; 5 | import net.minecraft.client.render.entity.EntityRenderDispatcher; 6 | import net.minecraft.client.util.math.MatrixStack; 7 | import net.minecraft.entity.Entity; 8 | import net.minecraft.world.WorldView; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | /** 14 | * Skips drawing blob shadows during the segmentation pass so ground blocks are 15 | * not darkened under entities in the colour map. 16 | */ 17 | @Mixin(EntityRenderDispatcher.class) 18 | public abstract class EntityRenderDispatcherShadowMixin { 19 | 20 | @Redirect( 21 | method = "render(Lnet/minecraft/entity/Entity;DDDFFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 22 | at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/EntityRenderDispatcher;renderShadow(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/entity/Entity;FFLnet/minecraft/world/WorldView;F)V") 23 | ) 24 | private void vereya$skipShadowWhenColourmap(MatrixStack matrices, 25 | VertexConsumerProvider vertexConsumers, 26 | Entity entity, 27 | float opacity, 28 | float tickDelta, 29 | WorldView world, 30 | float radius) { 31 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 32 | // Suppress shadow rendering during segmentation pass 33 | return; 34 | } 35 | // Call original method when not producing colour map 36 | EntityRenderDispatcherAccessor.invokeRenderShadow(matrices, vertexConsumers, entity, opacity, tickDelta, world, radius); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/RenderSystemShaderSwapMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import io.singularitynet.utils.TextureHelper; 5 | import net.minecraft.client.gl.ShaderProgram; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | import java.util.function.Supplier; 12 | 13 | /** 14 | * Globally enforces the annotate shader during the segmentation pass by 15 | * intercepting RenderSystem.setShader at the source. This covers draw paths 16 | * outside WorldRenderer (eg entity rendering) to ensure a stable per-type 17 | * colour for entities and blocks. 18 | */ 19 | @Mixin(RenderSystem.class) 20 | public abstract class RenderSystemShaderSwapMixin { 21 | 22 | private static final ThreadLocal VEREYA$GUARD = ThreadLocal.withInitial(() -> false); 23 | 24 | @Inject(method = "setShader", at = @At("HEAD"), cancellable = true) 25 | private static void vereya$swapToAnnotate(Supplier supplier, CallbackInfo ci) { 26 | if (VEREYA$GUARD.get()) return; 27 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) { 28 | return; 29 | } 30 | try { 31 | VEREYA$GUARD.set(true); 32 | ShaderProgram original = supplier.get(); 33 | if (original == null) { 34 | return; // let vanilla handle nulls 35 | } 36 | // When rendering entities, ensure a stable per-entity colour is pending 37 | if (TextureHelper.hasCurrentEntity()) { 38 | TextureHelper.setPendingColourForCurrentEntity(); 39 | } 40 | ShaderProgram annotate = TextureHelper.getAnnotateProgramForFormat(original.getFormat()); 41 | // Apply the currently pending uniform colour/debug to the annotate program 42 | TextureHelper.applyPendingColourToProgram(annotate); 43 | // Re-route the shader selection to the annotate program 44 | RenderSystem.setShader(() -> annotate); 45 | ci.cancel(); 46 | } finally { 47 | VEREYA$GUARD.set(false); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/CommandForDiscreteRobotNavigationImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.projectmalmo.MissionInit; 4 | import net.minecraft.client.MinecraftClient; 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | 8 | import java.util.Map; 9 | 10 | 11 | public class CommandForDiscreteRobotNavigationImplementation extends CommandBase { 12 | 13 | private static final Logger LOGGER = LogManager.getLogger(CommandForDiscreteRobotNavigationImplementation.class.getName()); 14 | 15 | private boolean moveAgent(String movement){ 16 | try { 17 | MinecraftClient client = MinecraftClient.getInstance(); 18 | LOGGER.debug("moving agent to " + movement); 19 | client.player.networkHandler.sendCommand("tp " + movement); 20 | return true; 21 | } catch (Exception e) { 22 | LogManager.getLogger().warn("Failed to move agent to " + movement); 23 | LogManager.getLogger().warn(e); 24 | return false; 25 | } 26 | } 27 | 28 | 29 | @Override 30 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) { 31 | 32 | if (verb == null || verb.length() == 0) 33 | { 34 | return false; 35 | } 36 | Map moveMap = Map.of( 37 | "movewest", "~-1 ~ ~", 38 | "moveeast", "~1 ~ ~", 39 | "movenorth", "~ ~ ~-1", 40 | "movesouth", "~ ~ ~1" 41 | ); 42 | String parameters[] = parameter.split(" "); 43 | if (parameters.length != 1) return false; 44 | // Now parse the command: 45 | String lowerVerb = verb.toLowerCase(); 46 | if (!moveMap.containsKey(lowerVerb)){ 47 | return false; 48 | } 49 | return moveAgent(moveMap.get(lowerVerb)); 50 | } 51 | 52 | @Override 53 | public boolean isOverriding() { 54 | return false; 55 | } 56 | 57 | @Override 58 | public void setOverriding(boolean b) { 59 | 60 | } 61 | 62 | @Override 63 | public void install(MissionInit currentMissionInit) { 64 | 65 | } 66 | 67 | @Override 68 | public void deinstall(MissionInit currentMissionInit) { 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromHotBarImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlers; 21 | 22 | import com.google.gson.JsonObject; 23 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 24 | import io.singularitynet.projectmalmo.MissionInit; 25 | import net.minecraft.client.MinecraftClient; 26 | 27 | /** Simple IObservationProducer class that returns a list of what is in the "hotbar". 28 | */ 29 | public class ObservationFromHotBarImplementation extends HandlerBase implements IObservationProducer 30 | { 31 | @Override 32 | public void prepare(MissionInit missionInit) {} 33 | 34 | @Override 35 | public void cleanup() {} 36 | 37 | @Override 38 | public void writeObservationsToJSON(JsonObject json, MissionInit missionInit) 39 | { 40 | ObservationFromFullInventoryImplementation.getInventoryJSON(json, "Hotbar_", 41 | MinecraftClient.getInstance().player.getInventory(), 9); 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/RewardGroup.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.IRewardProducer; 4 | import io.singularitynet.projectmalmo.MissionInit; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class RewardGroup extends HandlerBase implements IRewardProducer{ 9 | 10 | private ArrayList handlers; 11 | private boolean shareParametersWithChildren = false; 12 | 13 | public RewardGroup(){ this.handlers = new ArrayList();} 14 | 15 | protected void setShareParametersWithChildren(boolean share) 16 | { 17 | this.shareParametersWithChildren = share; 18 | } 19 | 20 | public void addRewardProducer(IRewardProducer handler){ 21 | this.handlers.add(handler); 22 | } 23 | 24 | public boolean isFixed(){ 25 | return false; 26 | } 27 | 28 | @Override 29 | public void setParentBehaviour(MissionBehaviour mb) 30 | { 31 | super.setParentBehaviour(mb); 32 | for (IRewardProducer han : this.handlers) 33 | ((HandlerBase)han).setParentBehaviour(mb); 34 | } 35 | 36 | @Override 37 | public boolean parseParameters(Object params) { 38 | // Normal handling: 39 | boolean ok = super.parseParameters(params); 40 | 41 | // Now, pass the params to each child handler, if that was requested: 42 | if (this.shareParametersWithChildren) { 43 | // AND the results, but without short-circuit evaluation. 44 | for (IRewardProducer han : this.handlers) { 45 | if (han instanceof HandlerBase) { 46 | ok &= ((HandlerBase) han).parseParameters(params); 47 | } 48 | } 49 | } 50 | return ok; 51 | } 52 | 53 | @Override 54 | public void cleanup() { 55 | 56 | } 57 | 58 | @Override 59 | public void prepare(MissionInit missionInit) { 60 | 61 | } 62 | 63 | @Override 64 | public void getReward(MultidimensionalReward reward) { 65 | for (IRewardProducer han : this.handlers){ 66 | han.getReward(reward); 67 | } 68 | } 69 | 70 | @Override 71 | public void trigger(Class clazz) { 72 | for (IRewardProducer han : this.handlers){ 73 | han.trigger(clazz); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/shaders/core/annotate.fsh: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | uniform sampler2D Sampler0; 4 | uniform int entityColourR; 5 | uniform int entityColourG; 6 | uniform int entityColourB; 7 | uniform int debugMode; 8 | uniform int atlasGrid; 9 | uniform int atlasLod; // MIP level used to derive per-sprite colour 10 | uniform int respectAlpha; // 1 = discard transparent texels (cutouts) 11 | 12 | in vec4 vertexColor; 13 | in vec2 texCoord0; 14 | 15 | // Use the same output name Minecraft core shaders expect 16 | out vec4 FragColor; 17 | 18 | vec4 colourFromAtlas(vec2 uv, int gridSize) { 19 | if (gridSize <= 0) { 20 | gridSize = 16; 21 | } 22 | float gx = floor(uv.x * float(gridSize)); 23 | float gy = floor(uv.y * float(gridSize)); 24 | float cell = gx + gy * float(gridSize); 25 | float base = 11.0; 26 | float r = mod(cell, base); 27 | cell = floor((cell - r) / base); 28 | float g = mod(cell, base); 29 | cell = floor((cell - g) / base); 30 | float b = mod(cell, base); 31 | return vec4(r / base, g / base, b / base, 1.0); 32 | } 33 | 34 | void main() { 35 | // Optionally discard fully transparent fragments for cutout geometry. 36 | if (respectAlpha != 0) { 37 | float a = texture(Sampler0, texCoord0).a; 38 | if (a < 0.1) { 39 | discard; 40 | } 41 | } 42 | if (debugMode == 1) { 43 | FragColor = vec4(1.0, 0.0, 1.0, 1.0); 44 | return; 45 | } 46 | if (debugMode == 2) { 47 | FragColor = vec4(fract(texCoord0 * 16.0), 0.0, 1.0); 48 | return; 49 | } 50 | if (debugMode == 3) { 51 | FragColor = vec4(fract(gl_FragCoord.xy / 32.0), 0.0, 1.0); 52 | return; 53 | } 54 | 55 | if (entityColourR >= 0) { 56 | FragColor = vec4(float(entityColourR) / 255.0, 57 | float(entityColourG) / 255.0, 58 | float(entityColourB) / 255.0, 59 | 1.0); 60 | return; 61 | } 62 | 63 | // Fallback path: derive a single, stable colour per atlas sprite 64 | // using the integer grid cell from texCoord0. This ensures all 65 | // fragments of the same block texture share one segmentation colour. 66 | int grid = atlasGrid; 67 | if (grid <= 0) { 68 | grid = 32; 69 | } 70 | FragColor = colourFromAtlas(texCoord0, grid); 71 | } 72 | -------------------------------------------------------------------------------- /src/test/resources/mission.xml: -------------------------------------------------------------------------------- 1 | truePig Sheep Cow Chicken Ozelot Rabbit VillagerCristina 1280 960 40127.0.0.1100000127.0.0.110401000104791087610090 2 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/utils/AddressHelper.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.utils; 21 | 22 | /** Class that helps to track and centralise our various IP address and port requirements.
23 | */ 24 | public class AddressHelper 25 | { 26 | static public final int MIN_MISSION_CONTROL_PORT = 10000; 27 | static public final int MIN_FREE_PORT = 10100; 28 | static public final int MAX_FREE_PORT = 11000; 29 | static private int missionControlPortOverride = 0; 30 | static private int missionControlPort = 0; 31 | 32 | static public int getMissionControlPortOverride() 33 | { 34 | return AddressHelper.missionControlPortOverride; 35 | } 36 | 37 | /** Get the actual port used for mission control, assuming it has been set. (Will return 0 if not.)
38 | * @return the port in use for mission control. 39 | */ 40 | static public int getMissionControlPort() 41 | { 42 | return AddressHelper.missionControlPort; 43 | } 44 | 45 | public static void setMissionControlPort(int mcPort) { 46 | missionControlPort = mcPort; 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromItemsImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonObject; 5 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 6 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 7 | import io.singularitynet.projectmalmo.MissionInit; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.item.Item; 10 | import net.minecraft.registry.Registry; 11 | 12 | import io.singularitynet.projectmalmo.ObservationFromItem; 13 | 14 | 15 | import java.util.List; 16 | import static net.minecraft.registry.Registries.ITEM; 17 | 18 | public class ObservationFromItemsImplementation extends HandlerBase implements IObservationProducer, ICommandHandler { 19 | private boolean sendRec; 20 | 21 | @Override 22 | public boolean isOverriding() { 23 | return false; 24 | } 25 | 26 | @Override 27 | public void setOverriding(boolean b) {} 28 | 29 | @Override 30 | public void install(MissionInit currentMissionInit) { sendRec = false; } 31 | 32 | @Override 33 | public void deinstall(MissionInit currentMissionInit) {} 34 | 35 | @Override 36 | public boolean execute(String command, MissionInit currentMissionInit) { 37 | String comm[] = command.split(" ", 2); 38 | if (comm.length == 2 && comm[0].equalsIgnoreCase(ObservationFromItem.ITEM_LIST.value())){ 39 | if (!comm[1].equalsIgnoreCase("off")) { 40 | this.sendRec = true; 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public void cleanup() {} 49 | 50 | @Override 51 | public void prepare(MissionInit missionInit) {} 52 | 53 | @Override 54 | public void writeObservationsToJSON(JsonObject json, MissionInit currentMissionInit) { 55 | if (!this.sendRec){ 56 | return; 57 | } 58 | this.sendRec = false; 59 | Registry str_ent = MinecraftClient.getInstance().world.getRegistryManager().get(ITEM.getKey()); 60 | List list_ent = str_ent.stream().toList(); 61 | JsonArray items = new JsonArray(); 62 | for (Item ent: list_ent) 63 | { 64 | String item_name = ent.toString().replace("minecraft:", ""); 65 | items.add(item_name); 66 | } 67 | json.add("item_list", items); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/CommandForWheeledRobotNavigationMobImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MessagePayload; 4 | import io.singularitynet.VereyaMessage; 5 | import io.singularitynet.VereyaMessageType; 6 | import io.singularitynet.projectmalmo.MissionInit; 7 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 8 | 9 | import java.util.Map; 10 | 11 | public class CommandForWheeledRobotNavigationMobImplementation extends CommandBase { 12 | 13 | 14 | public static class MotionMessage extends VereyaMessage { 15 | 16 | public MotionMessage(String parameters, String uuid, String value){ 17 | super(VereyaMessageType.CLIENT_MOVE, parameters); 18 | this.getData().put("uuid", uuid); 19 | this.getData().put("value", value); 20 | } 21 | 22 | public MotionMessage(Map data) { 23 | super(VereyaMessageType.CLIENT_MOVE, data.get("message")); 24 | this.getData().put("uuid", data.get("uuid")); 25 | this.getData().put("value", data.get("value")); 26 | } 27 | 28 | public String getUuid(){ 29 | return this.getData().get("uuid"); 30 | } 31 | 32 | public String getValue(){ 33 | return this.getData().get("value"); 34 | } 35 | 36 | public String getVerb(){ 37 | return this.getData().get("message"); 38 | } 39 | } 40 | 41 | @Override 42 | public boolean isOverriding() { 43 | return false; 44 | } 45 | 46 | @Override 47 | public void setOverriding(boolean b) { 48 | 49 | } 50 | 51 | @Override 52 | public void install(MissionInit currentMissionInit) { 53 | 54 | } 55 | 56 | @Override 57 | public void deinstall(MissionInit currentMissionInit) { 58 | 59 | } 60 | 61 | @Override 62 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) { 63 | if (verb == null || verb.length() == 0) { 64 | return false; 65 | } 66 | 67 | String[] params = parameter.split(" "); 68 | if (params.length != 2) { 69 | return false; 70 | } 71 | 72 | String entity_uuid = params[0]; 73 | parameter = params[1]; 74 | 75 | 76 | VereyaMessage vereyaMessage = new MotionMessage(verb, entity_uuid, parameter); 77 | 78 | ClientPlayNetworking.send(new MessagePayload(vereyaMessage)); 79 | return true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/FeatureRendererMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import io.singularitynet.utils.TextureHelper; 5 | import net.minecraft.client.gl.ShaderProgram; 6 | import net.minecraft.client.render.VertexConsumerProvider; 7 | import net.minecraft.client.render.entity.feature.FeatureRenderer; 8 | import net.minecraft.client.render.entity.model.EntityModel; 9 | import net.minecraft.client.util.math.MatrixStack; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.util.Identifier; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(FeatureRenderer.class) 18 | public abstract class FeatureRendererMixin { 19 | 20 | @Inject(method = "renderModel(Lnet/minecraft/client/render/entity/model/EntityModel;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFF)V", 21 | at = @At("HEAD")) 22 | private static void vereya$forceEntityColour(EntityModel model, 23 | Identifier texture, 24 | MatrixStack matrices, 25 | VertexConsumerProvider vertexConsumers, 26 | int light, 27 | T entity, 28 | float red, 29 | float green, 30 | float blue, 31 | CallbackInfo ci) { 32 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) return; 33 | // Ensure per-entity colour is locked before feature layer draws (armor, overlays, etc.). 34 | TextureHelper.setPendingColourForEntity(entity); 35 | ShaderProgram program = RenderSystem.getShader(); 36 | if (program != null) { 37 | TextureHelper.applyPendingColourToProgram(program); 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/BlockPlaceCommandsImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.projectmalmo.BlockPlaceCommand; 4 | import io.singularitynet.projectmalmo.MissionInit; 5 | import net.minecraft.client.MinecraftClient; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | 9 | public class BlockPlaceCommandsImplementation extends CommandBase { 10 | 11 | private static final Logger LOGGER = LogManager.getLogger(BlockPlaceCommandsImplementation.class.getName()); 12 | 13 | 14 | /* 15 | place block at x,y,z 16 | placement is replace, destroy, keep 17 | blockType is block name like minecraft:stone 18 | */ 19 | private void placeBlock(int x, int y, int z, String blockType, String placement){ 20 | // use SetBlock command 21 | // https://minecraft.gamepedia.com/Commands/setblock 22 | MinecraftClient client = MinecraftClient.getInstance(); 23 | LOGGER.debug("setting block at " + x + " " + y + " " + z + " " + placement); 24 | client.player.networkHandler.sendCommand("setblock " + x + " " + y + " " + z + " " + blockType + " " + placement); 25 | } 26 | 27 | @Override 28 | public boolean isOverriding() { 29 | return false; 30 | } 31 | 32 | @Override 33 | public void setOverriding(boolean b) { 34 | 35 | } 36 | 37 | @Override 38 | public void install(MissionInit currentMissionInit) { 39 | 40 | } 41 | 42 | @Override 43 | public void deinstall(MissionInit currentMissionInit) { 44 | 45 | } 46 | 47 | @Override 48 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) { 49 | if (!verb.equalsIgnoreCase(BlockPlaceCommand.PLACE_BLOCK.value())) 50 | { 51 | return false; 52 | } 53 | LOGGER.debug("block place command " + parameter); 54 | // parse parameters 55 | String[] params = parameter.split(" "); 56 | if (params.length != 5) 57 | { 58 | return false; 59 | } 60 | int x = Integer.parseInt(params[0]); 61 | int y = Integer.parseInt(params[1]); 62 | int z = Integer.parseInt(params[2]); 63 | String blockType = params[3]; 64 | String placement = params[4]; 65 | if (!(placement != "replace" || placement != "destroy" || placement != "keep")) 66 | { 67 | return false; 68 | } 69 | placeBlock(x, y, z, blockType, placement); 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ContinuousMovementCommandsImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | package io.singularitynet.MissionHandlers; 20 | 21 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 22 | import io.singularitynet.projectmalmo.ContinuousMovementCommands; 23 | 24 | 25 | public class ContinuousMovementCommandsImplementation extends CommandGroup implements ICommandHandler { 26 | 27 | public ContinuousMovementCommandsImplementation(){ 28 | setShareParametersWithChildren(true); // Pass our parameter block on to the following children: 29 | this.addCommandHandler(new CommandForAttackAndUseImplementation()); 30 | this.addCommandHandler(new CommandForWheeledRobotNavigationImplementation()); 31 | } 32 | 33 | @Override 34 | public boolean parseParameters(Object params) 35 | { 36 | super.parseParameters(params); 37 | 38 | if (params == null || !(params instanceof ContinuousMovementCommands)) 39 | return false; 40 | 41 | ContinuousMovementCommands cmparams = (ContinuousMovementCommands)params; 42 | setUpAllowAndDenyLists(cmparams.getModifierList()); 43 | return true; 44 | } 45 | 46 | @Override 47 | public boolean isFixed() { return true; } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/io/singularitynet/tests/TCPServer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.tests; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | import java.util.function.Consumer; 10 | 11 | /** Generic TCP server that reads length-prefixed packets and forwards them to a callback. */ 12 | public final class TCPServer implements Runnable { 13 | private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(TCPServer.class.getName()); 14 | private final int port; 15 | private final Consumer callback; 16 | private final AtomicBoolean stop = new AtomicBoolean(false); 17 | private Thread thread; 18 | 19 | public TCPServer(int port, Consumer callback) { 20 | this.port = port; 21 | this.callback = callback; 22 | } 23 | 24 | public Thread start(String name) { 25 | if (thread != null) return thread; 26 | thread = new Thread(this, name != null ? name : ("TCPServer-" + port)); 27 | thread.setDaemon(true); 28 | thread.start(); 29 | return thread; 30 | } 31 | 32 | public void stop() { 33 | stop.set(true); 34 | try { if (thread != null) thread.interrupt(); } catch (Throwable ignored) {} 35 | } 36 | 37 | @Override public void run() { 38 | try (ServerSocket ss = new ServerSocket(port)) { 39 | ss.setReuseAddress(true); 40 | while (!stop.get()) { 41 | try (Socket s = ss.accept()) { 42 | s.setTcpNoDelay(true); 43 | InputStream in = s.getInputStream(); 44 | while (!stop.get()) { 45 | int len = TestUtils.readIntBE(in); 46 | if (len <= 0 || len > 50_000_000) break; 47 | byte[] payload = TestUtils.readFully(in, len); 48 | long ts = System.nanoTime(); 49 | try { 50 | callback.accept(new TimestampedByteVector(ts, payload)); 51 | } catch (Throwable t) { 52 | LOG.warning("TCPServer callback error: " + t.getMessage()); 53 | } 54 | } 55 | } catch (Throwable t) { 56 | // continue accepting 57 | } 58 | } 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromFullStatsImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | package io.singularitynet.MissionHandlers; 20 | 21 | 22 | import com.google.gson.JsonObject; 23 | import io.singularitynet.Client.VereyaModClient; 24 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 25 | import io.singularitynet.projectmalmo.MissionInit; 26 | import io.singularitynet.utils.JSONWorldDataHelper; 27 | import net.minecraft.client.MinecraftClient; 28 | import net.minecraft.entity.player.PlayerEntity; 29 | 30 | /** 31 | * Simple IObservationProducer object that pings out a whole bunch of data.
32 | */ 33 | public class ObservationFromFullStatsImplementation extends HandlerBase implements IObservationProducer { 34 | 35 | @Override 36 | public void cleanup() { 37 | 38 | } 39 | 40 | @Override 41 | public void prepare(MissionInit missionInit) { 42 | 43 | } 44 | 45 | @Override 46 | public void writeObservationsToJSON(JsonObject json, MissionInit missionInit) 47 | { 48 | PlayerEntity player = MinecraftClient.getInstance().player; 49 | JSONWorldDataHelper.buildLifeStats(json, player); 50 | JSONWorldDataHelper.buildPositionStats(json, player); 51 | JSONWorldDataHelper.buildEnvironmentStats(json, player); 52 | JSONWorldDataHelper.buildControllableMobsData(json, VereyaModClient.getControllableEntities()); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/Client/ClientState.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.Client; 21 | 22 | 23 | import io.singularitynet.IState; 24 | 25 | /** Set of states used by MissionStateTracker to ensure the Mod remains in a valid state.
26 | * Note: these do not necessarily occur in the order presented here. 27 | * If adding states here, please also add a MissionStateEpisode class to MissionStateTracker, 28 | * and a line to the switch statement in MissionStateTracker.getStateEpisodeForState(). 29 | */ 30 | public enum ClientState implements IState { 31 | WAITING_FOR_MOD_READY, 32 | DORMANT, 33 | CREATING_HANDLERS, 34 | EVALUATING_WORLD_REQUIREMENTS, 35 | PAUSING_OLD_SERVER, 36 | CLOSING_OLD_SERVER, 37 | CREATING_NEW_WORLD, 38 | WAITING_FOR_SERVER_READY, 39 | RUNNING, 40 | IDLING, 41 | MISSION_ENDED, 42 | MISSION_ABORTED, 43 | WAITING_FOR_SERVER_MISSION_END, 44 | // Error conditions: 45 | ERROR_DUFF_HANDLERS, 46 | ERROR_INTEGRATED_SERVER_UNREACHABLE, 47 | ERROR_NO_WORLD, 48 | ERROR_CANNOT_CREATE_WORLD, 49 | ERROR_CANNOT_START_AGENT, 50 | ERROR_LOST_NETWORK_CONNECTION, 51 | ERROR_CANNOT_CONNECT_TO_SERVER, 52 | ERROR_TIMED_OUT_WAITING_FOR_WORLD_CREATE, 53 | ERROR_TIMED_OUT_WAITING_FOR_EPISODE_START, 54 | ERROR_TIMED_OUT_WAITING_FOR_EPISODE_PAUSE, 55 | ERROR_TIMED_OUT_WAITING_FOR_EPISODE_CLOSE, 56 | ERROR_TIMED_OUT_WAITING_FOR_MISSION_END, 57 | ERROR_LOST_AGENT, 58 | ERROR_LOST_VIDEO 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/GlStateManagerDrawMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.platform.GlStateManager; 4 | import io.singularitynet.utils.TextureHelper; 5 | import net.minecraft.client.gl.GlUniform; 6 | import net.minecraft.client.gl.ShaderProgram; 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(GlStateManager.class) 15 | public abstract class GlStateManagerDrawMixin { 16 | 17 | private static final Logger LOGGER = LogManager.getLogger(GlStateManagerDrawMixin.class); 18 | 19 | @Inject(method = "_drawElements", at = @At("HEAD")) 20 | private static void vereya$updateUniforms(int mode, int count, int type, long indices, CallbackInfo ci) { 21 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) { 22 | return; 23 | } 24 | TextureHelper.recordSegDraw(false); 25 | ShaderProgram program = com.mojang.blaze3d.systems.RenderSystem.getShader(); 26 | if (program == null) { 27 | return; 28 | } 29 | int[] pending = TextureHelper.getPendingColourRGB(); 30 | GlUniform r = program.getUniform("entityColourR"); 31 | GlUniform g = program.getUniform("entityColourG"); 32 | GlUniform b = program.getUniform("entityColourB"); 33 | if (r != null && g != null && b != null) { 34 | if (TextureHelper.getSegmentationDebugLevel() > 0) { 35 | LOGGER.trace("GlStateManagerDrawMixin: applying colour R:{} G:{} B:{}", pending[0], pending[1], pending[2]); 36 | } 37 | r.set(pending[0]); 38 | g.set(pending[1]); 39 | b.set(pending[2]); 40 | r.upload(); 41 | g.upload(); 42 | b.upload(); 43 | } 44 | GlUniform debug = program.getUniform("debugMode"); 45 | if (debug != null) { 46 | debug.set(TextureHelper.getSegmentationDebugLevel()); 47 | debug.upload(); 48 | } 49 | GlUniform alpha = program.getUniform("respectAlpha"); 50 | if (alpha != null) { 51 | alpha.set(TextureHelper.isRespectOpacity() ? 1 : 0); 52 | alpha.upload(); 53 | } 54 | GlUniform grid = program.getUniform("atlasGrid"); 55 | if (grid != null) { 56 | grid.set(32); 57 | grid.upload(); 58 | } 59 | GlUniform lod = program.getUniform("atlasLod"); 60 | if (lod != null) { 61 | lod.set(8); 62 | lod.upload(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/WorldRendererColourmapMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.render.Camera; 5 | import net.minecraft.client.render.GameRenderer; 6 | import net.minecraft.client.render.LightmapTextureManager; 7 | import net.minecraft.client.render.RenderTickCounter; 8 | import net.minecraft.client.render.WorldRenderer; 9 | import org.joml.Matrix4f; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | 15 | /** 16 | * Runs a dedicated segmentation render pass immediately before the default 17 | * world render when colour-map production is active. The second invocation of 18 | * {@link WorldRenderer#render} executes the normal pipeline so the on-screen 19 | * view remains unchanged. 20 | */ 21 | @Mixin(WorldRenderer.class) 22 | public abstract class WorldRendererColourmapMixin { 23 | 24 | private static final ThreadLocal VEREYA$SEGMENTATION_RENDERING = ThreadLocal.withInitial(() -> false); 25 | 26 | @Inject(method = "render", at = @At("TAIL")) 27 | private void vereya$renderColourMap(RenderTickCounter tickCounter, 28 | boolean renderBlockOutline, 29 | Camera camera, 30 | GameRenderer gameRenderer, 31 | LightmapTextureManager lightmap, 32 | Matrix4f positionMatrix, 33 | Matrix4f projectionMatrix, 34 | CallbackInfo ci) { 35 | if (!TextureHelper.isProducingColourMap()) { 36 | return; 37 | } 38 | if (VEREYA$SEGMENTATION_RENDERING.get()) { 39 | return; 40 | } 41 | 42 | VEREYA$SEGMENTATION_RENDERING.set(true); 43 | try { 44 | TextureHelper.colourmapFrame = true; 45 | TextureHelper.beginSegmentationPass(); 46 | Matrix4f segPosition = new Matrix4f(positionMatrix); 47 | Matrix4f segProjection = new Matrix4f(projectionMatrix); 48 | ((WorldRenderer) (Object) this).render(tickCounter, 49 | renderBlockOutline, 50 | camera, 51 | gameRenderer, 52 | lightmap, 53 | segPosition, 54 | segProjection); 55 | } finally { 56 | TextureHelper.endSegmentationPass(); 57 | TextureHelper.colourmapFrame = false; 58 | VEREYA$SEGMENTATION_RENDERING.set(false); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/EntityRendererMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.render.VertexConsumerProvider; 5 | import net.minecraft.client.render.entity.EntityRenderer; 6 | import net.minecraft.client.util.math.MatrixStack; 7 | import net.minecraft.entity.Entity; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | /** 14 | * Ensures we always mark the current entity during rendering so the 15 | * segmentation pipeline can assign a single, stable colour per entity type. 16 | * This complements the dispatcher hook and covers render paths where the 17 | * dispatcher injection might not fire for every draw call. 18 | */ 19 | @Mixin(EntityRenderer.class) 20 | public abstract class EntityRendererMixin { 21 | 22 | @Inject(method = "render(Lnet/minecraft/entity/Entity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 23 | at = @At("HEAD")) 24 | private void vereya$markCurrentEntity(T entity, 25 | float yaw, 26 | float tickDelta, 27 | MatrixStack matrices, 28 | VertexConsumerProvider vertexConsumers, 29 | int light, 30 | CallbackInfo ci) { 31 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 32 | TextureHelper.setCurrentEntity(entity); 33 | TextureHelper.setPendingColourForEntity(entity); 34 | TextureHelper.setStrictEntityDraw(true); 35 | } 36 | } 37 | 38 | @Inject(method = "render(Lnet/minecraft/entity/Entity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", 39 | at = @At("TAIL")) 40 | private void vereya$clearCurrentEntity(T entity, 41 | float yaw, 42 | float tickDelta, 43 | MatrixStack matrices, 44 | VertexConsumerProvider vertexConsumers, 45 | int light, 46 | CallbackInfo ci) { 47 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 48 | TextureHelper.setCurrentEntity(null); 49 | TextureHelper.setStrictEntityDraw(false); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/VertexBufferMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.client.texture.SpriteAtlasTexture; 5 | import net.minecraft.util.Identifier; 6 | import net.minecraft.client.gl.ShaderProgram; 7 | import net.minecraft.client.gl.VertexBuffer; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(VertexBuffer.class) 15 | public abstract class VertexBufferMixin { 16 | 17 | @ModifyVariable(method = "draw(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/client/gl/ShaderProgram;)V", 18 | at = @At("HEAD"), 19 | argsOnly = true) 20 | private ShaderProgram vereya$swapProgram(ShaderProgram original) { 21 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame || original == null) { 22 | return original; 23 | } 24 | ShaderProgram annotate = TextureHelper.getAnnotateProgramForFormat(original.getFormat()); 25 | TextureHelper.applyPendingColourToProgram(annotate); 26 | return annotate; 27 | } 28 | 29 | @Inject(method = "draw(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/client/gl/ShaderProgram;)V", at = @At("HEAD")) 30 | private void vereya$markBlockDrawStart(org.joml.Matrix4f pos, org.joml.Matrix4f proj, ShaderProgram program, CallbackInfo ci) { 31 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) return; 32 | // If rendering an entity, enforce entity colour and do NOT toggle block-draw based on atlas binds. 33 | if (TextureHelper.hasCurrentEntity()) { 34 | TextureHelper.setPendingColourForCurrentEntity(); 35 | return; 36 | } 37 | // Only consider a block draw if we actually have a current block type captured. 38 | Identifier last = TextureHelper.getLastBoundTexture(); 39 | boolean isAtlas = last != null && (SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE.equals(last) 40 | || (last.getPath() != null && last.getPath().contains("textures/atlas/"))); 41 | // Rely on BlockRenderManagerMixin to toggle block draws; do nothing here 42 | } 43 | 44 | @Inject(method = "draw(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/client/gl/ShaderProgram;)V", at = @At("TAIL")) 45 | private void vereya$markBlockDrawEnd(org.joml.Matrix4f pos, org.joml.Matrix4f proj, ShaderProgram program, CallbackInfo ci) { 46 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) return; 47 | TextureHelper.setDrawingBlock(false); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/VideoProducerImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import com.mojang.blaze3d.platform.GlStateManager; 4 | import io.singularitynet.MissionHandlerInterfaces.IVideoProducer; 5 | import io.singularitynet.projectmalmo.MissionInit; 6 | import io.singularitynet.projectmalmo.VideoProducer; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gl.Framebuffer; 9 | import org.lwjgl.BufferUtils; 10 | import org.lwjgl.opengl.GL11; 11 | 12 | import java.nio.ByteBuffer; 13 | import java.nio.FloatBuffer; 14 | 15 | import static org.lwjgl.opengl.GL12.GL_BGRA; 16 | 17 | public class VideoProducerImplementation extends HandlerBase implements IVideoProducer 18 | { 19 | private VideoProducer videoParams; 20 | private FloatBuffer depthBuffer; 21 | 22 | @Override 23 | public boolean parseParameters(Object params) 24 | { 25 | if (params == null || !(params instanceof VideoProducer)) 26 | return false; 27 | this.videoParams = (VideoProducer) params; 28 | 29 | return true; 30 | } 31 | 32 | @Override 33 | public VideoType getVideoType() 34 | { 35 | return VideoType.VIDEO; 36 | } 37 | 38 | @Override 39 | public int[] writeFrame(MissionInit missionInit, ByteBuffer buffer) 40 | { 41 | if (!this.videoParams.isWantDepth()) 42 | { 43 | return writeRGBFrame(buffer); // Just return the simple RGB, 3bpp image. 44 | } 45 | else 46 | throw new RuntimeException("Depth map not implemented"); 47 | } 48 | 49 | @Override 50 | public int getWidth() 51 | { 52 | return this.videoParams.getWidth(); 53 | } 54 | 55 | @Override 56 | public int getHeight() { return this.videoParams.getHeight(); } 57 | 58 | private int[] writeRGBFrame(ByteBuffer buffer) 59 | { 60 | Framebuffer framebuffer = MinecraftClient.getInstance().getFramebuffer(); 61 | int i = framebuffer.textureWidth; 62 | int j = framebuffer.textureHeight; 63 | GlStateManager._readPixels(0, 0, i, j, GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer); 64 | int[] sizes = new int[2]; 65 | sizes[0] = i; 66 | sizes[1] = j; 67 | return sizes; 68 | } 69 | 70 | @Override 71 | public void prepare(MissionInit missionInit) 72 | { 73 | boolean useDepth = this.videoParams.isWantDepth(); 74 | // Create a buffer for retrieving the depth map, if requested: 75 | if (useDepth) 76 | this.depthBuffer = BufferUtils.createFloatBuffer(this.videoParams.getWidth() * this.videoParams.getHeight()); 77 | // Set the requested camera position 78 | // Minecraft.getMinecraft().gameSettings.thirdPersonView = this.videoParams.getViewpoint(); 79 | } 80 | 81 | @Override 82 | public void cleanup() {} 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IVideoProducer.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlerInterfaces; 21 | 22 | import io.singularitynet.projectmalmo.MissionInit; 23 | 24 | import java.nio.ByteBuffer; 25 | 26 | /** Interface for objects which are responsible for providing Minecraft video data. 27 | */ 28 | public interface IVideoProducer 29 | { 30 | enum VideoType 31 | { 32 | VIDEO, 33 | DEPTH_MAP, 34 | LUMINANCE, 35 | COLOUR_MAP 36 | }; 37 | 38 | /** Get the type of video frames returned.*/ 39 | VideoType getVideoType(); 40 | 41 | /** 42 | * Get a frame of video from Minecraft. 43 | * 44 | * @param missionInit the MissionInit object for the currently running mission, which may contain parameters for the video requirements. 45 | * @return an array of bytes representing this frame.
46 | * (The format is unspecified; it is up to the IVideoProducer implementation and the agent to agree on how the data is formatted.) 47 | */ 48 | 49 | int[] writeFrame(MissionInit missionInit, ByteBuffer buffer); 50 | 51 | /** Get the requested width of the video frames returned.*/ 52 | int getWidth(); 53 | 54 | /** Get the requested height of the video frames returned.*/ 55 | int getHeight(); 56 | 57 | /** Called once before the mission starts - use for any necessary initialisation.*/ 58 | void prepare(MissionInit missionInit); 59 | 60 | /** Called once after the mission ends - use for any necessary cleanup.*/ 61 | void cleanup(); 62 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlerInterfaces/IWorldGenerator.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlerInterfaces; 21 | 22 | import io.singularitynet.projectmalmo.MissionInit; 23 | 24 | /** Interface for objects which can determine the world structure for the Minecraft mission. 25 | */ 26 | public interface IWorldGenerator { 27 | 28 | /** Provide a world - eg by loading it from a basemap file, or by creating one procedurally. 29 | * @param missionInit the MissionInit object for the currently running mission, which may contain parameters for the observation requirements. 30 | * @return true if a world has been created, false otherwise 31 | */ 32 | public boolean createWorld(MissionInit missionInit); 33 | 34 | /** Determine whether or not createWorld should be called.
35 | * If this returns false, createWorld will not be called, and the player will simply be respawned in the current world. 36 | * It provides a means for a "quick reset" - eg, the world builder could decide that the state of the current world is close enough to the 37 | * desired state that there is no point building a whole new world. 38 | * @param missionInit the MissionInit object for the currently running mission, which may contain parameters for the observation requirements. 39 | * @return true if the world should be created, false otherwise. 40 | */ 41 | public boolean shouldCreateWorld(MissionInit missionInit, Object genOptions); 42 | 43 | public String getErrorDetails(); 44 | 45 | public Object getOptions(); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/AgentQuitFromTouchingBlockTypeImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.IWantToQuit; 4 | import io.singularitynet.projectmalmo.*; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Vec3d; 9 | import org.apache.logging.log4j.LogManager; 10 | 11 | import java.util.HashSet; 12 | import java.util.List; 13 | 14 | public class AgentQuitFromTouchingBlockTypeImplementation extends HandlerBase implements IWantToQuit { 15 | 16 | HashSet qbSet; 17 | 18 | @Override 19 | public void cleanup() { 20 | 21 | } 22 | 23 | 24 | @Override 25 | public String getOutcome() { 26 | String block = getBlockUnderPlayer(); 27 | return "Agent touched " + block; 28 | } 29 | 30 | @Override 31 | public void prepare(MissionInit missionInit) { 32 | 33 | } 34 | 35 | @Override 36 | public boolean parseParameters(Object params){ 37 | if (params == null || !(params instanceof AgentQuitFromTouchingBlockType)) { 38 | return false; 39 | } 40 | AgentQuitFromTouchingBlockType aqparams = (AgentQuitFromTouchingBlockType)params; 41 | List quitBlocks = aqparams.getBlock(); 42 | this.qbSet = new HashSet(); 43 | if(!(quitBlocks == null || quitBlocks.isEmpty())){ 44 | for (BlockSpecWithDescription quitBlock : quitBlocks){ 45 | String blockType = quitBlock.getType().getFirst().toString().toLowerCase(); 46 | this.qbSet.add(blockType); 47 | } 48 | } 49 | return true; 50 | } 51 | @Override 52 | public boolean doIWantToQuit(MissionInit currentMissionInit) { 53 | String blockType = getBlockUnderPlayer(); 54 | if (blockType == null || blockType.isEmpty()){ 55 | return true; 56 | } 57 | if (this.qbSet == null || this.qbSet.isEmpty()){ 58 | return false; 59 | } 60 | return this.qbSet.contains(blockType); 61 | } 62 | 63 | private String getBlockUnderPlayer(){ 64 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 65 | if (player == null){ 66 | LogManager.getLogger().error("player is null"); 67 | return ""; 68 | } 69 | Vec3d playerPos = player.getPos(); 70 | //substract 0.5 because agent can be standing on a slab 71 | BlockPos blockPos = BlockPos.ofFloored(playerPos.subtract(0, 0.5, 0)); 72 | String blockType = player.getWorld().getBlockState(blockPos).getBlock().getTranslationKey().toLowerCase(); 73 | String[] parts = blockType.split("\\.", 3); 74 | blockType = (parts.length > 2) ? parts[2] : ""; 75 | return blockType; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/events/ServerEntityEventsVereya.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.events; 2 | 3 | import net.fabricmc.fabric.api.event.Event; 4 | import net.fabricmc.fabric.api.event.EventFactory; 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.server.world.ServerWorld; 7 | import net.minecraft.util.ActionResult; 8 | import net.minecraft.util.profiler.Profiler; 9 | 10 | public interface ServerEntityEventsVereya { 11 | 12 | /** 13 | * Called when an Entity is about to be loaded into a ServerWorld. 14 | * 15 | *

Can be used to cancel entity loading. 16 | */ 17 | public static final Event BEFORE_ENTITY_LOAD = EventFactory.createArrayBacked(ServerEntityEventsVereya.class, callbacks -> (entity, world) -> { 18 | if (EventFactory.isProfilingEnabled()) { 19 | final Profiler profiler = world.getProfiler(); 20 | profiler.push("fabricServerEntityLoadBefore"); 21 | 22 | for (ServerEntityEventsVereya callback : callbacks) { 23 | profiler.push(EventFactory.getHandlerName(callback)); 24 | ActionResult result = callback.interact(entity, world); 25 | profiler.pop(); 26 | if (result != ActionResult.PASS) { 27 | return result; 28 | } 29 | } 30 | profiler.pop(); 31 | } else { 32 | for (ServerEntityEventsVereya callback : callbacks) { 33 | ActionResult result = callback.interact(entity, world); 34 | if (result != ActionResult.PASS) { 35 | return result; 36 | } 37 | } 38 | } 39 | return ActionResult.PASS; 40 | }); 41 | 42 | public static final Event BEFORE_ENTITY_ADD = EventFactory.createArrayBacked(ServerEntityEventsVereya.class, callbacks -> (entity, world) -> { 43 | if (EventFactory.isProfilingEnabled()) { 44 | final Profiler profiler = world.getProfiler(); 45 | profiler.push("fabricServerEntityAddBefore"); 46 | 47 | for (ServerEntityEventsVereya callback : callbacks) { 48 | profiler.push(EventFactory.getHandlerName(callback)); 49 | ActionResult result = callback.interact(entity, world); 50 | profiler.pop(); 51 | if (result != ActionResult.PASS) { 52 | return result; 53 | } 54 | } 55 | profiler.pop(); 56 | } else { 57 | for (ServerEntityEventsVereya callback : callbacks) { 58 | ActionResult result = callback.interact(entity, world); 59 | if (result != ActionResult.PASS) { 60 | return result; 61 | } 62 | } 63 | } 64 | return ActionResult.PASS; 65 | }); 66 | 67 | ActionResult interact( Entity entity, ServerWorld world); 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromSolidnessImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonObject; 5 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 6 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 7 | import io.singularitynet.projectmalmo.MissionInit; 8 | import io.singularitynet.projectmalmo.ObservationFromSolid; 9 | import net.minecraft.block.Block; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.registry.Registry; 12 | import org.apache.logging.log4j.LogManager; 13 | import org.apache.logging.log4j.Logger; 14 | 15 | import java.util.List; 16 | 17 | import static net.minecraft.registry.Registries.BLOCK; 18 | 19 | public class ObservationFromSolidnessImplementation extends HandlerBase implements IObservationProducer, ICommandHandler { 20 | private static final Logger LOGGER = LogManager.getLogger(ObservationFromSolidnessImplementation.class); 21 | private boolean sendRec; 22 | 23 | @Override 24 | public boolean isOverriding() {return false;} 25 | 26 | @Override 27 | public void setOverriding(boolean b) {} 28 | 29 | @Override 30 | public void install(MissionInit currentMissionInit) {sendRec = false;} 31 | 32 | @Override 33 | public void deinstall(MissionInit currentMissionInit) {} 34 | 35 | @Override 36 | public boolean execute(String command, MissionInit currentMissionInit) { 37 | String comm[] = command.split(" ", 2); 38 | if (comm.length == 2 && comm[0].equalsIgnoreCase(ObservationFromSolid.SOLID.value()) && 39 | !comm[1].equalsIgnoreCase("off")) { 40 | this.sendRec = true; 41 | LOGGER.debug("ObservationFromSolidnessImplementation set Flag"); 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public void cleanup() {} 49 | 50 | @Override 51 | public void prepare(MissionInit missionInit) {} 52 | 53 | @Override 54 | public void writeObservationsToJSON(JsonObject json, MissionInit currentMissionInit) { 55 | if (!this.sendRec){ 56 | return; 57 | } 58 | LOGGER.debug("ObservationFromSolidnessImplementation writing observation"); 59 | this.sendRec = false; 60 | Registry blocks = MinecraftClient.getInstance().world.getRegistryManager().get(BLOCK.getKey()); 61 | List list_blocks = blocks.stream().toList(); 62 | JsonArray nonsolid_blocks = new JsonArray(); 63 | for (Block ent: list_blocks) 64 | { 65 | if (!ent.getDefaultState().blocksMovement()) 66 | { 67 | String item_name = ent.toString().replaceAll("Block|minecraft:|\\{|\\}", ""); 68 | nonsolid_blocks.add(item_name); 69 | } 70 | } 71 | json.add("nonsolid_blocks", nonsolid_blocks); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/Schemas/MissionEnded.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Stores multi-dimensional rewards as a map of int:double where dimension is a positive integer. 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/GameOptionsMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import net.minecraft.client.option.GameOptions; 4 | import net.minecraft.client.option.KeyBinding; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Mutable; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | @Mixin(GameOptions.class) 10 | public interface GameOptionsMixin { 11 | @Accessor("attackKey") @Mutable 12 | public void setKeyAttack(KeyBinding key); 13 | 14 | @Accessor("attackKey") 15 | public KeyBinding getKeyAttack(); 16 | 17 | @Accessor("useKey") @Mutable 18 | public void setKeyUse(KeyBinding key); 19 | 20 | @Accessor("useKey") 21 | public KeyBinding getKeyUse(); 22 | 23 | @Accessor("hotbarKeys") @Mutable 24 | public void setKeysHotbar(KeyBinding[] keys); 25 | 26 | @Accessor("hotbarKeys") 27 | public KeyBinding[] getKeysHotbar(); 28 | 29 | @Accessor("swapHandsKey") 30 | public KeyBinding getKeySwapHands(); 31 | 32 | @Accessor("swapHandsKey") @Mutable 33 | public void setKeySwapHands(KeyBinding key); 34 | 35 | // setters for movement commands 36 | @Accessor("forwardKey") @Mutable 37 | public void setKeyForward(KeyBinding key); 38 | 39 | @Accessor("backKey") @Mutable 40 | public void setKeyBack(KeyBinding key); 41 | 42 | @Accessor("leftKey") @Mutable 43 | public void setKeyLeft(KeyBinding key); 44 | 45 | @Accessor("rightKey") @Mutable 46 | public void setKeyRight(KeyBinding key); 47 | 48 | @Accessor("jumpKey") @Mutable 49 | public void setKeyJump(KeyBinding key); 50 | 51 | @Accessor("sneakKey") @Mutable 52 | public void setKeySneak(KeyBinding key); 53 | 54 | @Accessor("sprintKey") @Mutable 55 | public void setKeySprint(KeyBinding key); 56 | 57 | // getters for the movement commands 58 | @Accessor("forwardKey") 59 | public KeyBinding getKeyForward(); 60 | 61 | @Accessor("backKey") 62 | public KeyBinding getKeyBack(); 63 | 64 | @Accessor("leftKey") 65 | public KeyBinding getKeyLeft(); 66 | 67 | @Accessor("rightKey") 68 | public KeyBinding getKeyRight(); 69 | 70 | @Accessor("jumpKey") 71 | public KeyBinding getKeyJump(); 72 | 73 | @Accessor("sprintKey") 74 | public KeyBinding getKeySprint(); 75 | 76 | @Accessor("sneakKey") 77 | public KeyBinding getKeySneak(); 78 | 79 | // getter and setter for inventory 80 | @Accessor("inventoryKey") 81 | public KeyBinding getKeyInventory(); 82 | 83 | @Accessor("inventoryKey") @Mutable 84 | public void setKeyInventory(KeyBinding key); 85 | 86 | // getter and setter for drop 87 | @Accessor("dropKey") 88 | public KeyBinding getKeyDrop(); 89 | 90 | @Accessor("dropKey") @Mutable 91 | public void setKeyDrop(KeyBinding key); 92 | 93 | @Accessor("pickItemKey") @Mutable 94 | public void setKeyPickItem(KeyBinding key); 95 | 96 | @Accessor("pickItemKey") 97 | public KeyBinding getKeyPickItem(); 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/BlockRenderManagerMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import io.singularitynet.utils.TextureHelper; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.render.block.BlockRenderManager; 6 | import net.minecraft.client.util.math.MatrixStack; 7 | import net.minecraft.client.render.VertexConsumer; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.random.Random; 10 | import net.minecraft.world.BlockRenderView; 11 | import net.minecraft.registry.Registries; 12 | import net.minecraft.util.Identifier; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | 18 | /** 19 | * Captures the current block type string when rendering blocks so the 20 | * segmentation path can assign a stable per-type colour rather than a 21 | * UV-derived colour that varies across sprites. 22 | */ 23 | @Mixin(BlockRenderManager.class) 24 | public abstract class BlockRenderManagerMixin { 25 | 26 | @Inject(method = "renderBlock", at = @At("HEAD")) 27 | private void vereya$captureBlockType(BlockState state, 28 | BlockPos pos, 29 | BlockRenderView world, 30 | MatrixStack matrices, 31 | VertexConsumer vertexConsumer, 32 | boolean cull, 33 | Random random, 34 | CallbackInfo ci) { 35 | Identifier id = Registries.BLOCK.getId(state.getBlock()); 36 | if (id != null) { 37 | TextureHelper.setCurrentBlockType(id.toString()); 38 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 39 | TextureHelper.setDrawingBlock(true); 40 | TextureHelper.setStrictBlockDraw(true); 41 | // Set a stable per-type colour for the block being drawn 42 | TextureHelper.setPendingColourForCurrentBlock(); 43 | } 44 | } 45 | } 46 | 47 | @Inject(method = "renderBlock", at = @At("TAIL")) 48 | private void vereya$clearBlockFlag(BlockState state, 49 | BlockPos pos, 50 | BlockRenderView world, 51 | MatrixStack matrices, 52 | VertexConsumer vertexConsumer, 53 | boolean cull, 54 | Random random, 55 | CallbackInfo ci) { 56 | if (TextureHelper.isProducingColourMap() && TextureHelper.colourmapFrame) { 57 | TextureHelper.setDrawingBlock(false); 58 | TextureHelper.setStrictBlockDraw(false); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/resources/Schemas/MissionInit.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | A MissionInit message tells the agent and client to talk to each other to complete the supplied mission. 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | A unique ID to disambiguate experiments. 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | The role this client will play in a multi-agent mission. 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | The MinecraftServerConnection is used to tell other clients where to find their server. 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | A ClientAgentConnection tells the client and the agent the IP address and ports they should talk to each other on. 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/WorldUtil.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.registry.DynamicRegistryManager; 5 | import net.minecraft.registry.RegistryKeys; 6 | import net.minecraft.resource.DataConfiguration; 7 | import net.minecraft.world.Difficulty; 8 | import net.minecraft.world.GameMode; 9 | import net.minecraft.world.GameRules; 10 | import net.minecraft.world.dimension.DimensionOptionsRegistryHolder; 11 | import net.minecraft.world.gen.GeneratorOptions; 12 | import net.minecraft.world.gen.WorldPresets; 13 | import net.minecraft.world.level.LevelInfo; 14 | import org.apache.logging.log4j.LogManager; 15 | 16 | import java.util.Properties; 17 | import java.util.UUID; 18 | 19 | 20 | public class WorldUtil { 21 | public static void createLevel(boolean hardcore, Long seed, Difficulty difficulty) throws Exception { 22 | UUID uuid = UUID.randomUUID(); 23 | String worldName = uuid.toString().substring(0, 5); 24 | String levelName = "Vereya-test" + worldName; 25 | GameRules gameRules = new GameRules(); 26 | MinecraftClient client = MinecraftClient.getInstance(); 27 | LevelInfo levelInfo = new LevelInfo(levelName.trim(), 28 | GameMode.DEFAULT, hardcore, difficulty, true, 29 | gameRules, 30 | DataConfiguration.SAFE_MODE); 31 | LogManager.getLogger().debug("creating world with seed " + seed); 32 | GeneratorOptions generatorOptions = new GeneratorOptions(seed, true, false); 33 | client.createIntegratedServerLoader().createAndStart(levelName, levelInfo, generatorOptions, WorldUtil::getDefaultOverworldOptions, client.currentScreen); 34 | } 35 | 36 | public static DimensionOptionsRegistryHolder getDefaultOverworldOptions(DynamicRegistryManager dynamicRegistryManager) { 37 | return dynamicRegistryManager.get(RegistryKeys.WORLD_PRESET).entryOf(WorldPresets.DEFAULT).value().createDimensionsRegistryHolder(); 38 | } 39 | 40 | public static DimensionOptionsRegistryHolder getFlatOverworldOptions(DynamicRegistryManager dynamicRegistryManager) { 41 | return dynamicRegistryManager.get(RegistryKeys.WORLD_PRESET).entryOf(WorldPresets.FLAT).value().createDimensionsRegistryHolder(); 42 | } 43 | 44 | public static void createLevelFlat(boolean hardcore, Long seed, 45 | Difficulty difficulty, Properties properties) { 46 | UUID uuid = UUID.randomUUID(); 47 | String worldName = uuid.toString().substring(0, 5); 48 | String levelName = "Vereya-test" + worldName; 49 | GameRules gameRules = new GameRules(); 50 | MinecraftClient client = MinecraftClient.getInstance(); 51 | LevelInfo levelInfo = new LevelInfo(levelName.trim(), GameMode.DEFAULT, 52 | hardcore, difficulty, 53 | true, gameRules, DataConfiguration.SAFE_MODE); 54 | GeneratorOptions generatorOptions = new GeneratorOptions(seed, true, false); 55 | client.createIntegratedServerLoader().createAndStart(levelName, levelInfo, generatorOptions, WorldUtil::getFlatOverworldOptions, client.currentScreen); 56 | /* 57 | DynamicRegistryManager.Impl impl = DynamicRegistryManager.create(); 58 | 59 | GeneratorOptions generatorOptions = getGeneratorOptions(properties); 60 | MinecraftClient.getInstance().createWorld(worldName, levelInfo, impl, generatorOptions); 61 | */ 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromRecipesImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonPrimitive; 5 | import com.google.gson.JsonObject; 6 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 7 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 8 | import io.singularitynet.projectmalmo.MissionInit; 9 | import io.singularitynet.projectmalmo.ObservationFromRecipe; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.recipe.Ingredient; 13 | import net.minecraft.recipe.RecipeEntry; 14 | import net.minecraft.util.collection.DefaultedList; 15 | 16 | import java.util.List; 17 | 18 | class ObservationFromRecipesImplementation extends HandlerBase implements IObservationProducer, ICommandHandler { 19 | private boolean sendRec; 20 | private int counter; 21 | 22 | @Override 23 | public void cleanup() { 24 | 25 | } 26 | 27 | @Override 28 | public void prepare(MissionInit missionInit) { 29 | 30 | } 31 | 32 | @Override 33 | public void writeObservationsToJSON(JsonObject json, MissionInit currentMissionInit) { 34 | if (!this.sendRec){ 35 | return; 36 | } 37 | this.sendRec = false; 38 | List> result = MinecraftClient.getInstance().world.getRecipeManager().values().stream().toList(); 39 | JsonArray recipes = new JsonArray(); 40 | for (RecipeEntry r: result) { 41 | JsonObject rec = new JsonObject(); // recipe 42 | ItemStack out = r.value().getResult(MinecraftClient.getInstance().world.getRegistryManager()); 43 | rec.add("name", new JsonPrimitive(out.getItem().getTranslationKey())); 44 | rec.add("count", new JsonPrimitive(out.getCount())); 45 | DefaultedList ingredients = r.value().getIngredients(); 46 | JsonArray ingArray = new JsonArray(); // ingredients 47 | for(Ingredient ingrid: ingredients) { 48 | JsonArray ingStacks = new JsonArray(); 49 | for(ItemStack s:ingrid.getMatchingStacks()){ 50 | JsonObject ing = new JsonObject(); 51 | ing.add("type", new JsonPrimitive(s.getItem().getTranslationKey())); 52 | ing.add("count", new JsonPrimitive(s.getCount())); 53 | ingStacks.add(ing); 54 | } 55 | ingArray.add(ingStacks); 56 | } 57 | rec.add("ingredients", ingArray); 58 | rec.add("recipe_type", new JsonPrimitive(r.value().getType().toString())); 59 | rec.add("group", new JsonPrimitive(r.value().getGroup())); 60 | recipes.add(rec); 61 | } 62 | json.add("recipes", recipes); 63 | } 64 | 65 | @Override 66 | public boolean isOverriding() { 67 | return false; 68 | } 69 | 70 | @Override 71 | public void setOverriding(boolean b) { 72 | 73 | } 74 | 75 | @Override 76 | public void install(MissionInit currentMissionInit) { 77 | sendRec = false; 78 | } 79 | 80 | @Override 81 | public void deinstall(MissionInit currentMissionInit) { 82 | 83 | } 84 | 85 | @Override 86 | public boolean execute(String command, MissionInit currentMissionInit) { 87 | String comm[] = command.split(" ", 2); 88 | if (comm.length == 2 && comm[0].equalsIgnoreCase(ObservationFromRecipe.RECIPES.value()) && 89 | !comm[1].equalsIgnoreCase("off")) { 90 | this.sendRec = true; 91 | return true; 92 | } 93 | return false; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/SimpleCraftCommandsImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | package io.singularitynet.MissionHandlers; 20 | 21 | 22 | import io.singularitynet.*; 23 | 24 | import io.singularitynet.projectmalmo.MissionInit; 25 | import io.singularitynet.projectmalmo.SimpleCraftCommand; 26 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 27 | import net.minecraft.server.network.ServerPlayerEntity; 28 | import org.apache.logging.log4j.LogManager; 29 | import org.apache.logging.log4j.Logger; 30 | 31 | import java.util.Map; 32 | 33 | 34 | public class SimpleCraftCommandsImplementation extends CommandBase implements IVereyaMessageListener { 35 | private boolean isOverriding; 36 | // Directly reference a log4j logger. 37 | private static final Logger LOGGER = LogManager.getLogger(SimpleCraftCommandsImplementation.class.getName()); 38 | 39 | 40 | @Override 41 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) 42 | { 43 | if (verb.equalsIgnoreCase(SimpleCraftCommand.CRAFT.value())) 44 | { 45 | LOGGER.info("Sending crafting message " + verb); 46 | ClientPlayNetworking.send(new MessagePayload(new SimpleCraftCommandsImplementationServer.CraftMessage(parameter))); 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | @Override 53 | public void onMessage(VereyaMessageType messageType, Map data) { 54 | throw new RuntimeException("Unexpected message to client"); 55 | } 56 | 57 | @Override 58 | public void onMessage(VereyaMessageType messageType, Map data, ServerPlayerEntity player) { 59 | throw new RuntimeException("calling server-side message handler on client"); 60 | } 61 | 62 | @Override 63 | public boolean isOverriding() 64 | { 65 | return this.isOverriding; 66 | } 67 | 68 | @Override 69 | public void setOverriding(boolean b) 70 | { 71 | this.isOverriding = b; 72 | } 73 | 74 | @Override 75 | public void install(MissionInit currentMissionInit) { 76 | LOGGER.debug("Installing SimpleCraftCommandsImplementation"); 77 | } 78 | 79 | @Override 80 | public void deinstall(MissionInit currentMissionInit) { 81 | LOGGER.debug("Denstalling SimpleCraftCommandsImplementation"); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromComposite.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlers; 21 | 22 | 23 | import java.util.ArrayList; 24 | import java.util.HashMap; 25 | 26 | import com.google.gson.JsonObject; 27 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 28 | import io.singularitynet.projectmalmo.MissionInit; 29 | 30 | /** 31 | * Composite class that concatenates the results from multiple ObservationProducer objects.
32 | */ 33 | public class ObservationFromComposite extends HandlerBase implements IObservationProducer 34 | { 35 | private ArrayList producers; 36 | 37 | /** 38 | * Add another ObservationProducer object.
39 | * 40 | * @param producer the observation producing object to add to the mix. 41 | */ 42 | public void addObservationProducer(IObservationProducer producer) 43 | { 44 | if (this.producers == null) 45 | { 46 | this.producers = new ArrayList(); 47 | } 48 | this.producers.add(producer); 49 | } 50 | 51 | @Override 52 | public void writeObservationsToJSON(JsonObject json, MissionInit missionInit) 53 | { 54 | if (this.producers == null) 55 | return; 56 | 57 | for (IObservationProducer producer : this.producers) 58 | { 59 | producer.writeObservationsToJSON(json, missionInit); 60 | } 61 | } 62 | 63 | @Override 64 | public void prepare(MissionInit missionInit) 65 | { 66 | for (IObservationProducer producer : this.producers) 67 | { 68 | producer.prepare(missionInit); 69 | } 70 | } 71 | 72 | @Override 73 | public void cleanup() 74 | { 75 | for (IObservationProducer producer : this.producers) 76 | { 77 | producer.cleanup(); 78 | } 79 | } 80 | 81 | @Override 82 | public void appendExtraServerInformation(HashMap map) 83 | { 84 | for (IObservationProducer producer : this.producers) 85 | { 86 | if (producer instanceof HandlerBase) 87 | ((HandlerBase)producer).appendExtraServerInformation(map); 88 | } 89 | } 90 | 91 | public boolean isFixed() 92 | { 93 | return false; // Return true to stop MissionBehaviour from adding new handlers to this group. 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/RewardForTouchingBlockTypeImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.IRewardProducer; 4 | import io.singularitynet.projectmalmo.BlockSpecWithRewardAndBehaviour; 5 | import io.singularitynet.projectmalmo.MissionInit; 6 | import io.singularitynet.projectmalmo.RewardForTouchingBlockType; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | import net.minecraft.util.math.BlockPos; 10 | import net.minecraft.util.math.Vec3d; 11 | import org.apache.logging.log4j.LogManager; 12 | 13 | import java.util.HashMap; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | 17 | public class RewardForTouchingBlockTypeImplementation extends HandlerBase implements IRewardProducer { 18 | 19 | HashMap rewardBlocks; 20 | HashSet onceOnlyBlocks; 21 | Integer dimension; 22 | 23 | public RewardForTouchingBlockTypeImplementation(){ 24 | this.rewardBlocks = new HashMap(); 25 | this.onceOnlyBlocks = new HashSet(); 26 | this.dimension = 0; 27 | } 28 | 29 | @Override 30 | public void cleanup() { 31 | 32 | } 33 | 34 | @Override 35 | public boolean parseParameters(Object params){ 36 | if (params == null || !(params instanceof RewardForTouchingBlockType)) { 37 | return false; 38 | } 39 | RewardForTouchingBlockType rtbparams = (RewardForTouchingBlockType)params; 40 | List blocks = rtbparams.getBlock(); 41 | if (this.rewardBlocks == null) this.rewardBlocks = new HashMap(); 42 | for (BlockSpecWithRewardAndBehaviour block : blocks){ 43 | String blockType = block.getType().getFirst().toString().toLowerCase(); 44 | this.rewardBlocks.put(blockType, block); 45 | } 46 | this.dimension = rtbparams.getDimension(); 47 | return true; 48 | } 49 | 50 | @Override 51 | public void prepare(MissionInit missionInit) { 52 | 53 | } 54 | 55 | @Override 56 | public void getReward(MultidimensionalReward reward) { 57 | String blockType = getBlockUnderPlayer(); 58 | if (blockType.isEmpty() || !(this.rewardBlocks.containsKey(blockType))) return; 59 | BlockSpecWithRewardAndBehaviour rewardBlock = this.rewardBlocks.get(blockType); 60 | //handle onceOnly behaviour 61 | String behav = rewardBlock.getBehaviour().value(); 62 | if (rewardBlock.getBehaviour().value().equals("onceOnly")){ 63 | if (this.onceOnlyBlocks.contains(blockType)) return; 64 | this.onceOnlyBlocks.add(blockType); 65 | } 66 | reward.add(this.dimension, rewardBlock.getReward().floatValue()); 67 | // TODO: implement other behaviours 68 | } 69 | 70 | @Override 71 | public void trigger(Class clazz) { 72 | 73 | } 74 | 75 | private String getBlockUnderPlayer(){ 76 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 77 | if (player == null){ 78 | LogManager.getLogger().error("player is null"); 79 | return ""; 80 | } 81 | Vec3d playerPos = player.getPos(); 82 | //substract 0.5 because agent can be standing on a slab 83 | BlockPos blockPos = BlockPos.ofFloored(playerPos.subtract(0, 0.5, 0)); 84 | String blockType = player.getWorld().getBlockState(blockPos).getBlock().getTranslationKey().toLowerCase(); 85 | String[] parts = blockType.split("\\.", 3); 86 | blockType = (parts.length > 2) ? parts[2] : ""; 87 | return blockType; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Automatically build the project and run any configured tests for every push 2 | # and submitted pull request. This can help catch issues that only occur on 3 | # certain platforms or Java versions, and provides a first line of defence 4 | # against bad commits. 5 | 6 | name: build and test 7 | on: [pull_request, push] 8 | defaults: 9 | run: 10 | shell: bash -l {0} 11 | 12 | jobs: 13 | build: 14 | name: build 15 | runs-on: self-hosted 16 | strategy: 17 | matrix: 18 | # Use these Java versions 19 | java: [ 21, ] # Current Java LTS & minimum supported by Minecraft 20 | steps: 21 | - name: lock file 22 | run: lockfile /tmp/minecraft-test-lock 23 | - name: checkout repository 24 | uses: actions/checkout@v2 25 | - name: validate gradle wrapper 26 | uses: gradle/wrapper-validation-action@v1 27 | - name: setup jdk ${{ matrix.java }} 28 | uses: actions/setup-java@v1 29 | with: 30 | java-version: ${{ matrix.java }} 31 | - name: make gradle wrapper executable 32 | if: ${{ runner.os != 'Windows' }} 33 | run: chmod +x ./gradlew 34 | - name: build 35 | run: ./gradlew build && md5sum $GITHUB_WORKSPACE/build/libs/* 36 | - name: copy server cache 37 | run: cp -r ~/server/ . ; git checkout server 38 | - name: install vereya 39 | run: rm /home/tester/.minecraft/mods/* && cp $GITHUB_WORKSPACE/build/libs/* /home/tester/.minecraft/mods/ && 40 | rsync -v $GITHUB_WORKSPACE/build/libs/* $GITHUB_WORKSPACE/server/mods/ 41 | - name: install fabric 42 | run: rsync -v $GITHUB_WORKSPACE/fabric/* /home/tester/.minecraft/mods/ && 43 | rsync -v $GITHUB_WORKSPACE/fabric/* $GITHUB_WORKSPACE/server/mods/ && 44 | md5sum $GITHUB_WORKSPACE/server/mods/* && 45 | md5sum /home/tester/.minecraft/mods/* 46 | - name: remove lock 47 | if: failure() 48 | run: rm -f /tmp/minecraft-test-lock 49 | - name: start minecraft 50 | run: ./launch.sh & 51 | env: 52 | DISPLAY: :99 53 | GITHUB_WORKSPACE: $GITHUB_WORKSPACE 54 | - name: start minecraft server 55 | run: cd server && ./launch.sh & 56 | env: 57 | GITHUB_WORKSPACE: $GITHUB_WORKSPACE 58 | - name: checkout tagilmo 59 | uses: actions/checkout@v3 60 | with: 61 | repository: trueagi-io/minecraft-demo 62 | path: minecraft-demo 63 | - name: install tagilmo 64 | run: conda activate py31 && cd $GITHUB_WORKSPACE/minecraft-demo && pip install . 65 | - name: Check server health 66 | run: | 67 | timeout 60s bash -c "while ! curl -v -s http://localhost:25565/health 2>&1 | grep -q 'Empty reply'; do sleep 5s; done" 68 | - name: run test 69 | run: | 70 | ps a|grep [j]ava && 71 | conda activate py31 && cd $GITHUB_WORKSPACE/minecraft-demo/tests/vereya && 72 | python run_tests.py 73 | - name: save java logs 74 | if: always() 75 | uses: actions/upload-artifact@v4 76 | with: 77 | name: java.log 78 | path: logs/app.log 79 | - name: save python logs 80 | if: always() 81 | uses: actions/upload-artifact@v4 82 | with: 83 | name: PythonLog 84 | path: minecraft-demo/tests/vereya/app.log 85 | - name: save test observations 86 | uses: actions/upload-artifact@v4 87 | with: 88 | name: TestObservations 89 | path: minecraft-demo/tests/vereya/observations/observations.txt 90 | 91 | - name: cleanup 92 | if: success() 93 | run: rm -r `pwd`/* 94 | 95 | - name: remove lock 96 | if: always() 97 | run: rm -f /tmp/minecraft-test-lock 98 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ChatCommandsImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | 21 | package io.singularitynet.MissionHandlers; 22 | 23 | 24 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 25 | import io.singularitynet.projectmalmo.ChatCommand; 26 | import io.singularitynet.projectmalmo.ChatCommands; 27 | import io.singularitynet.projectmalmo.MissionInit; 28 | import net.minecraft.client.MinecraftClient; 29 | import net.minecraft.client.network.ClientPlayerEntity; 30 | import org.apache.logging.log4j.LogManager; 31 | import org.apache.logging.log4j.Logger; 32 | 33 | /** Chat commands allow the players to broadcast text messages. */ 34 | public class ChatCommandsImplementation extends CommandBase implements ICommandHandler 35 | { 36 | private boolean isOverriding; 37 | private static final Logger LOGGER = LogManager.getLogger(); 38 | 39 | @Override 40 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) 41 | { 42 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 43 | if (player == null) 44 | { 45 | return false; 46 | } 47 | 48 | if (!verb.equalsIgnoreCase(ChatCommand.CHAT.value())) 49 | { 50 | return false; 51 | } 52 | String command = null; 53 | if (parameter.startsWith("/")) { 54 | command = parameter.substring(1); 55 | LOGGER.debug("sending command: " + command); 56 | player.networkHandler.sendCommand(command); 57 | } else { 58 | command = parameter; 59 | player.networkHandler.sendChatMessage(command); 60 | } 61 | return true; 62 | } 63 | 64 | @Override 65 | public boolean parseParameters(Object params) 66 | { 67 | if (params == null || !(params instanceof ChatCommands)) 68 | return false; 69 | 70 | ChatCommands cparams = (ChatCommands)params; 71 | setUpAllowAndDenyLists(cparams.getModifierList()); 72 | return true; 73 | } 74 | 75 | @Override 76 | public void install(MissionInit missionInit) 77 | { 78 | } 79 | 80 | @Override 81 | public void deinstall(MissionInit missionInit) 82 | { 83 | } 84 | 85 | @Override 86 | public boolean isOverriding() 87 | { 88 | return this.isOverriding; 89 | } 90 | 91 | @Override 92 | public void setOverriding(boolean b) 93 | { 94 | this.isOverriding = b; 95 | } 96 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/mixin/RenderSystemDrawMixin.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.mixin; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.Logger; 6 | import io.singularitynet.utils.TextureHelper; 7 | import net.minecraft.client.gl.GlUniform; 8 | import net.minecraft.client.gl.ShaderProgram; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(RenderSystem.class) 15 | public abstract class RenderSystemDrawMixin { 16 | 17 | private static final Logger LOGGER = LogManager.getLogger(RenderSystemDrawMixin.class); 18 | 19 | @Inject(method = "drawElements(III)V", at = @At("HEAD")) 20 | private static void vereya$applyAnnotateUniforms(int mode, int count, int type, CallbackInfo ci) { 21 | if (!TextureHelper.isProducingColourMap() || !TextureHelper.colourmapFrame) { 22 | return; 23 | } 24 | TextureHelper.recordSegDraw(true); 25 | // If drawing blocks and we know the current block type, force a stable 26 | // per-type colour regardless of the last bound texture. 27 | if (TextureHelper.hasCurrentEntity()) { 28 | // Rendering an entity: force a stable per-entity colour 29 | TextureHelper.setPendingColourForCurrentEntity(); 30 | } else { 31 | // No current entity: try entity fallback from last bound texture; else atlas 32 | net.minecraft.util.Identifier last = TextureHelper.getLastBoundTexture(); 33 | boolean fallbackApplied = false; 34 | if (last != null) { 35 | String p = last.getPath(); 36 | if (p != null && p.startsWith("textures/entity/")) { 37 | // Let applyPendingColourToProgram resolve fallback to a stable colour 38 | // by leaving pending untouched here; it will pick up last-bound id. 39 | fallbackApplied = true; 40 | } 41 | } 42 | // Default to atlas fallback colours for blocks/non-entity draws 43 | if (!fallbackApplied) TextureHelper.setPendingForBlockAtlas(); 44 | } 45 | ShaderProgram program = RenderSystem.getShader(); 46 | if (program == null) { 47 | return; 48 | } 49 | TextureHelper.applyPendingColourToProgram(program); 50 | int[] pending = TextureHelper.getPendingColourRGB(); 51 | GlUniform r = program.getUniform("entityColourR"); 52 | GlUniform g = program.getUniform("entityColourG"); 53 | GlUniform b = program.getUniform("entityColourB"); 54 | if (r != null && g != null && b != null) { 55 | if (TextureHelper.getSegmentationDebugLevel() > 0) { 56 | LOGGER.trace("RenderSystemDrawMixin: applying colour R:{} G:{} B:{}", pending[0], pending[1], pending[2]); 57 | } 58 | r.set(pending[0]); 59 | g.set(pending[1]); 60 | b.set(pending[2]); 61 | r.upload(); 62 | g.upload(); 63 | b.upload(); 64 | } 65 | GlUniform debug = program.getUniform("debugMode"); 66 | if (debug != null) { 67 | debug.set(TextureHelper.getSegmentationDebugLevel()); 68 | debug.upload(); 69 | } 70 | GlUniform alpha = program.getUniform("respectAlpha"); 71 | if (alpha != null) { 72 | alpha.set(TextureHelper.isRespectOpacity() ? 1 : 0); 73 | alpha.upload(); 74 | } 75 | GlUniform grid = program.getUniform("atlasGrid"); 76 | if (grid != null) { grid.set(128); grid.upload(); } 77 | GlUniform lod = program.getUniform("atlasLod"); 78 | if (lod != null) { 79 | lod.set(8); 80 | lod.upload(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /api.md: -------------------------------------------------------------------------------- 1 | # architecture and api overview 2 | 3 | Vereya consists of two parts: java mod that works in minecraft process 4 | and client library VereyaPython.so which communicates with the mod. 5 | 6 | High-level api for interaction with the client library 7 | https://github.com/trueagi-io/minecraft-demo/tree/main/tagilmo 8 | 9 | These classes are used to control and query the game: 10 | 11 | * AgentHost 12 | * WorldState 13 | * MissionSpec 14 | * ClientPool 15 | * TimestampedVideoFrame 16 | 17 | ### AgentHost 18 | main interface to the mod, used to start and set up the game 19 | 20 | ### MissionSpec 21 | Determines minecraft world settings, and which of commands and observations will be available during the mission. 22 | 23 | Commands and observations are defined in __AgentHandlers__ section of Mission xml string. 24 | see [Mission.xsd](src/main/resources/Schemas/Mission.xsd) for xml structure 25 | 26 | **observations:** 27 | ObservationFromFullStats 28 | ObservationFromHotBar 29 | ObservationFromFullInventory 30 | ObservationFromGrid 31 | ObservationFromNearbyEntities 32 | ObservationFromRay 33 | 34 | VideoProducer 35 | 36 | **commands:** 37 | ContinuousMovementCommands 38 | InventoryCommands 39 | ChatCommands 40 | SimpleCraftCommand 41 | MissionQuitCommands 42 | 43 | 44 | ### WorldState 45 | * is_mission_running: bool 46 | * has_mission_begun: bool 47 | * observations: dict 48 | contains the last observations except video frame and rewards 49 | * rewards: float 50 | * video_frames: TimestampedVideoFrame 51 | contains the last video frame 52 | 53 | 54 | ### TimestampedVideoFrame 55 | timestamp 56 | width 57 | height 58 | channels 59 | xPos 60 | yPos 61 | zPos 62 | yaw 63 | pitch 64 | frametype - int, 0 RGB, 1 depth, 2 LUMINANCE 65 | modelViewMatrix - opengl model-view matrix 66 | calibrationMatrix - opengl perspective projection matrix 67 | pixels 68 | 69 | 70 | ### ObservationFromRay 71 | 72 | Observation from ray creates LineOfSight field in the world data. 73 | 74 | Fields: 75 | 76 | "hitType": "MISS", "BLOCK", "ENTITY" 77 | "type": - entity of block id "sheep", "dirt" etc 78 | if hitType is "BLOCK" then json will contain some of the properties from this file 79 | https://maven.fabricmc.net/docs/yarn-1.18+build.1/net/minecraft/state/property/Properties.html 80 | "x" 81 | "y" 82 | "z" - corresponding coordinates 83 | "distance" - distance from camera(not from the player's body!!) to the hit point 84 | "inRange" - boolean, true if distance < 4.5 or 6 if game is run with extended reach 85 | 86 | ###ObservationFromNearbyEntities 87 | 88 | worldState will contain : pairs 89 | 90 | Entity' properties: 91 | "yaw" 92 | "x" 93 | "y" 94 | "z" 95 | "pitch" 96 | "id" - internal in-game id 97 | "type" - i.g. "cow" 98 | "motionX" 99 | "motionY" 100 | "motionZ" 101 | "name" - empty if it's a mob 102 | 103 | 104 | ###ObservationFromGrid 105 | 106 | Returns cubic block grid centred on the player. 107 | Default is 3x3x3. (One cube all around the player.) 108 | Blocks are returned as a 1D array, in order 109 | along the x, then z, then y axes. 110 | Data will be returned in an array called "Cells" 111 | each element of array is a string = type of the block 112 | 113 | ###ObservationFromFullInventory 114 | 115 | Returns array named "inventory". 116 | Each element of the array has properties: 117 | 118 | "type" - item's name 119 | "index" - it's cell in the inventory, cells 0-9 are from the hotbar 120 | "quantity" - 121 | "inventory" - inventory's name 122 | 123 | ###ObservationFromHotBar 124 | 125 | The same as ObservationFromFullInventory, but limited to the hotbar cells 126 | 127 | ###ObservationFromFullStats 128 | 129 | adds player's stats to the json 130 | 131 | "Life" 132 | "Score" 133 | "Food" 134 | "XP" 135 | "Air" 136 | "Name" 137 | 138 | "XPos" 139 | "YPos" 140 | "ZPos" 141 | "Pitch" 142 | "Yaw" 143 | 144 | "WorldTime" 145 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/ObservationFromChatImplementation.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.MissionHandlerInterfaces.IObservationProducer; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonPrimitive; 6 | import com.google.gson.JsonObject; 7 | import io.singularitynet.MyChatHud; 8 | import io.singularitynet.mixin.InGameHudMixin; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.gui.hud.ChatHud; 11 | import io.singularitynet.projectmalmo.MissionInit; 12 | import net.minecraft.client.network.ClientPlayerEntity; 13 | import net.minecraft.text.Text; 14 | import org.apache.logging.log4j.LogManager; 15 | import org.apache.logging.log4j.Logger; 16 | 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | 20 | public class ObservationFromChatImplementation extends HandlerBase implements IObservationProducer, io.singularitynet.MissionHandlerInterfaces.ClientChatListener { 21 | private static final Logger LOGGER = LogManager.getLogger(); 22 | private ChatHud backup; 23 | private class ChatMessage 24 | { 25 | public String messageType; 26 | public String messageContent; 27 | public ChatMessage(String messageType, String messageContent) 28 | { 29 | this.messageType = messageType; 30 | this.messageContent = messageContent; 31 | } 32 | } 33 | 34 | private ArrayList chatMessagesReceived = new ArrayList(); 35 | 36 | @Override 37 | public void cleanup() { 38 | ChatHud hud = MinecraftClient.getInstance().inGameHud.getChatHud(); 39 | 40 | if (hud instanceof MyChatHud){ 41 | MyChatHud hud1 = (MyChatHud) hud; 42 | hud1.getListeners().remove(this); 43 | } 44 | 45 | if (backup != null) { 46 | ((InGameHudMixin) (MinecraftClient.getInstance().inGameHud)).setChatHud(backup); 47 | backup = null; 48 | } 49 | } 50 | 51 | @Override 52 | public void prepare(MissionInit missionInit) { 53 | backup = MinecraftClient.getInstance().inGameHud.getChatHud(); 54 | MyChatHud myHud = new MyChatHud(MinecraftClient.getInstance()); 55 | myHud.getListeners().add(this); 56 | ((InGameHudMixin) (MinecraftClient.getInstance().inGameHud)).setChatHud(myHud); 57 | } 58 | 59 | @Override 60 | public void writeObservationsToJSON(JsonObject json, MissionInit missionInit) 61 | { 62 | if (!this.chatMessagesReceived.isEmpty()) 63 | { 64 | HashMap> lists = new HashMap>(); 65 | for (ChatMessage message : this.chatMessagesReceived) 66 | { 67 | ArrayList arr = lists.get(message.messageType); 68 | if (arr == null) 69 | { 70 | arr = new ArrayList(); 71 | lists.put(message.messageType, arr); 72 | } 73 | arr.add(message.messageContent); 74 | } 75 | for (String key : lists.keySet()) 76 | { 77 | JsonArray jarr = new JsonArray(); 78 | for (String message : lists.get(key)) 79 | { 80 | jarr.add(new JsonPrimitive(message)); 81 | LOGGER.debug("sending CHAT observation " + key + ":" + message); 82 | } 83 | json.add(key, jarr); 84 | } 85 | this.chatMessagesReceived.clear(); 86 | } 87 | } 88 | 89 | @Override 90 | public void onChatMessage(Text text) { 91 | LOGGER.info("got chat message " + text.getString()); 92 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 93 | if (player != null){ 94 | String playerName = player.getName().getString(); 95 | String msgString = text.getString().replaceAll("<" + playerName + ">", "").strip(); 96 | this.chatMessagesReceived.add(new ChatMessage("Chat", msgString)); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/SimpleCraftCommandsImplementationServer.java: -------------------------------------------------------------------------------- 1 | package io.singularitynet.MissionHandlers; 2 | 3 | import io.singularitynet.IVereyaMessageListener; 4 | import io.singularitynet.VereyaMessage; 5 | import io.singularitynet.VereyaMessageType; 6 | import io.singularitynet.SidesMessageHandler; 7 | import io.singularitynet.projectmalmo.MissionInit; 8 | import io.singularitynet.utils.CraftingHelper; 9 | import net.minecraft.recipe.Recipe; 10 | import net.minecraft.recipe.RecipeType; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | import org.apache.logging.log4j.LogManager; 13 | import org.apache.logging.log4j.Logger; 14 | 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class SimpleCraftCommandsImplementationServer extends CommandBase implements IVereyaMessageListener { 19 | private static final Logger LOGGER = LogManager.getLogger(SimpleCraftCommandsImplementationServer.class.getName()); 20 | 21 | public static class CraftMessage extends VereyaMessage 22 | { 23 | 24 | public CraftMessage(String parameters) 25 | { 26 | super(VereyaMessageType.CLIENT_CRAFT, parameters); 27 | } 28 | 29 | public CraftMessage(String parameters, String fuel_type){ 30 | super(VereyaMessageType.CLIENT_CRAFT, parameters); 31 | this.getData().put("fuel_type", fuel_type); 32 | } 33 | } 34 | 35 | @Override 36 | public void onMessage(VereyaMessageType messageType, Map data) { 37 | throw new RuntimeException("Calling client message handler on server"); 38 | } 39 | 40 | @Override 41 | public void onMessage(VereyaMessageType messageType, Map data, ServerPlayerEntity player) 42 | { 43 | LOGGER.debug("Got crafting message " + messageType + " " + data.get("message")); 44 | // Try crafting recipes first: 45 | List matching_recipes; 46 | String[] split = data.get("message").split(" "); 47 | matching_recipes = CraftingHelper.getRecipesForRequestedOutput(split[0], false, player); 48 | 49 | // crafting doensn't require furnace or campfire 50 | for (Recipe recipe : matching_recipes.stream().filter(recipe -> {return recipe.getType() == RecipeType.CRAFTING;}).toList()) 51 | { 52 | if (CraftingHelper.attemptCrafting(player, recipe)) 53 | return; 54 | } 55 | 56 | // campfire cooking, requires campfire, doesn't consume furnace 57 | for (Recipe recipe : matching_recipes.stream().filter(recipe -> {return recipe.getType() == RecipeType.CAMPFIRE_COOKING;}).toList()) { 58 | if (CraftingHelper.attemptCampfireCooking(player, recipe)) 59 | return; 60 | } 61 | 62 | // Now try smelting recipes that require furnace 63 | for (Recipe recipe : matching_recipes.stream().filter(recipe -> {return recipe.getType() == RecipeType.SMELTING;}).toList()) 64 | { 65 | String fuel_type = "birch_log"; 66 | if (split.length > 1) { 67 | fuel_type = split[1]; 68 | } 69 | 70 | if (CraftingHelper.attemptSmelting(player, recipe, fuel_type)) 71 | return; 72 | } 73 | 74 | // blasting is the same as smelting 75 | } 76 | 77 | @Override 78 | public boolean isOverriding() { 79 | return false; 80 | } 81 | 82 | @Override 83 | public void setOverriding(boolean b) { 84 | 85 | } 86 | 87 | 88 | @Override 89 | public void install(MissionInit missionInit) 90 | { 91 | LOGGER.debug("Installing SimpleCraftCommandsImplementationServer"); 92 | SidesMessageHandler.client2server.registerForMessage(this, VereyaMessageType.CLIENT_CRAFT); 93 | } 94 | 95 | @Override 96 | public void deinstall(MissionInit missionInit) { 97 | LOGGER.debug("Deinstalling SimpleCraftCommandsImplementationServer"); 98 | SidesMessageHandler.client2server.deregisterForMessage(this, VereyaMessageType.CLIENT_CRAFT); 99 | } 100 | 101 | @Override 102 | protected boolean onExecute(String verb, String parameter, MissionInit missionInit) { 103 | throw new RuntimeException("calling onExecute on server"); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/EpisodeEventWrapper.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet; 21 | 22 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; 23 | import net.minecraft.server.MinecraftServer; 24 | import org.apache.logging.log4j.LogManager; 25 | 26 | import java.util.concurrent.locks.ReentrantReadWriteLock; 27 | 28 | /** Class that is responsible for catching all the Forge events we require (server ticks, client ticks, etc) 29 | * and passing them on to the current episode.
30 | * Doing it this way saves us having to register/deregister each individual episode, which was causing race-condition vulnerabilities. 31 | */ 32 | public class EpisodeEventWrapper implements 33 | ServerTickEvents.EndTick, 34 | ServerTickEvents.StartTick { 35 | /** The current episode, if there is one. */ 36 | protected StateEpisode stateEpisode = null; 37 | 38 | /** Lock to prevent the state episode being changed whilst mid event.
39 | * This does not prevent multiple events from *reading* the stateEpisode, but 40 | * it won't allow *writing* to the stateEpisode whilst it is being read. 41 | */ 42 | protected ReentrantReadWriteLock stateEpisodeLock = new ReentrantReadWriteLock(); 43 | 44 | /** Set our state to a new episode.
45 | * This waits on the stateEpisodeLock to prevent the episode being changed whilst in use. 46 | * @param stateEpisode the episode to switch to. 47 | * @return the previous state episode. 48 | */ 49 | public StateEpisode setStateEpisode(StateEpisode stateEpisode) 50 | { 51 | this.stateEpisodeLock.writeLock().lock(); 52 | StateEpisode lastEpisode = this.stateEpisode; 53 | this.stateEpisode = stateEpisode; 54 | this.stateEpisodeLock.writeLock().unlock(); 55 | return lastEpisode; 56 | } 57 | 58 | public EpisodeEventWrapper(){ 59 | LogManager.getLogger().info("Setting up EpisodeEventWrapper for Server events"); 60 | ServerTickEvents.END_SERVER_TICK.register(server -> {this.onEndTick(server);}); 61 | ServerTickEvents.START_SERVER_TICK.register(server -> {this.onStartTick(server);}); 62 | } 63 | 64 | @Override 65 | public void onEndTick(MinecraftServer server) { 66 | // Pass the event on to the active episode, if there is one: 67 | this.stateEpisodeLock.readLock().lock(); 68 | if (this.stateEpisode != null && this.stateEpisode.isLive()) 69 | { 70 | this.stateEpisode.onServerTick(server); 71 | } 72 | this.stateEpisodeLock.readLock().unlock(); 73 | } 74 | 75 | @Override 76 | public void onStartTick(MinecraftServer server) { 77 | // Pass the event on to the active episode, if there is one: 78 | this.stateEpisodeLock.readLock().lock(); 79 | if (this.stateEpisode != null && this.stateEpisode.isLive()) 80 | { 81 | this.stateEpisode.onServerTickStart(server); 82 | } 83 | this.stateEpisodeLock.readLock().unlock(); 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/FlatWorldGeneratorImplementation.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | package io.singularitynet.MissionHandlers; 20 | 21 | 22 | import io.singularitynet.MissionHandlerInterfaces.IWorldGenerator; 23 | import io.singularitynet.projectmalmo.FlatWorldGenerator; 24 | import io.singularitynet.projectmalmo.MissionInit; 25 | import net.minecraft.client.MinecraftClient; 26 | import net.minecraft.world.Difficulty; 27 | import org.apache.logging.log4j.LogManager; 28 | 29 | import java.util.Properties; 30 | 31 | public class FlatWorldGeneratorImplementation extends HandlerBase implements IWorldGenerator 32 | { 33 | FlatWorldGenerator fwparams; 34 | 35 | @Override 36 | public boolean parseParameters(Object params) 37 | { 38 | if (params == null || !(params instanceof FlatWorldGenerator)) 39 | return false; 40 | 41 | this.fwparams = (FlatWorldGenerator)params; 42 | String generatorString = this.fwparams.getGeneratorString(); 43 | generatorString = generatorString.replace("%ESC", "\""); 44 | this.fwparams.setGeneratorString(generatorString); 45 | return true; 46 | } 47 | 48 | @Override 49 | public boolean createWorld(MissionInit missionInit) 50 | { 51 | long seed = DefaultWorldGeneratorImplementation.getWorldSeedFromString(this.fwparams.getSeed()); 52 | 53 | try{ 54 | LogManager.getLogger().info("Creating flat world"); 55 | Properties props = new Properties(); 56 | props.setProperty("level-type", "flat"); 57 | props.setProperty("level-seed", String.valueOf(seed)); 58 | props.setProperty("generator-settings", this.fwparams.getGeneratorString()); 59 | WorldUtil.createLevelFlat(false, seed, Difficulty.NORMAL, props); 60 | return true; 61 | } catch (RuntimeException e) { 62 | LogManager.getLogger().error(e); 63 | return false; 64 | } 65 | } 66 | 67 | @Override 68 | public boolean shouldCreateWorld(MissionInit missionInit, Object genProps) 69 | { 70 | if (this.fwparams != null && this.fwparams.isForceReset()) 71 | return true; 72 | 73 | if (MinecraftClient.getInstance().world == null || genProps == null) 74 | return true; // Definitely need to create a world if there isn't one in existence! 75 | 76 | if (FlatWorldGenerator.class.isInstance(genProps)){ 77 | FlatWorldGenerator oldProps = (FlatWorldGenerator)genProps; 78 | if (this.fwparams.getGeneratorString() != oldProps.getGeneratorString()) 79 | return true; 80 | if (this.fwparams.getSeed() != oldProps.getSeed()) 81 | return true; 82 | return false; 83 | } 84 | return true; 85 | } 86 | 87 | @Override 88 | public String getErrorDetails() 89 | { 90 | return ""; // Currently no error exit points, so never anything to report. 91 | } 92 | 93 | @Override 94 | public Object getOptions() { 95 | return fwparams; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/io/singularitynet/MissionHandlers/CommandBase.java: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // Copyright (c) 2016 Microsoft Corporation 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | // associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | // -------------------------------------------------------------------------------------------------- 19 | 20 | package io.singularitynet.MissionHandlers; 21 | 22 | import io.singularitynet.MissionHandlerInterfaces.ICommandHandler; 23 | import io.singularitynet.projectmalmo.CommandListModifier; 24 | import io.singularitynet.projectmalmo.MissionInit; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | 30 | /** Base class for Command handlers - provides XML parsing to build up an allowed/disallowed list of commands. 31 | */ 32 | public abstract class CommandBase extends HandlerBase implements ICommandHandler 33 | { 34 | private List commandsAllowList = null; 35 | private List commandsDenyList = null; 36 | 37 | protected boolean isCommandAllowed(String verb) 38 | { 39 | if (this.commandsDenyList == null && this.commandsAllowList == null) 40 | return true; // Everything is enabled by default 41 | 42 | if (this.commandsDenyList != null && this.commandsDenyList.contains(verb.toLowerCase())) { 43 | System.out.println("command verb on the deny-list: "+verb); 44 | return false; // If the verb is on the deny list, disallow it 45 | } 46 | 47 | if (this.commandsAllowList != null && !this.commandsAllowList.contains(verb.toLowerCase())) { 48 | System.out.println("command verb not on the allow-list: "+verb); 49 | for(String v : this.commandsAllowList ) 50 | System.out.println("("+v+" is allowed)"); 51 | return false; // If the command isn't on the allow list, disallow it 52 | } 53 | 54 | // Otherwise, all is good: 55 | return true; 56 | } 57 | 58 | public boolean execute(String command, MissionInit missionInit) 59 | { 60 | if (command == null || command.length() == 0) 61 | { 62 | return false; 63 | } 64 | 65 | // We expect the first word to be the command, and the rest of the string to be parameters, if present. 66 | String[] parms = command.split(" ", 2); 67 | String verb = parms[0].toLowerCase(); 68 | String parameter = (parms.length > 1) ? parms[1] : ""; 69 | 70 | // Also chuck out any commands which aren't on our allow list / are on our deny list: 71 | if (!isCommandAllowed(verb)) 72 | { 73 | return false; 74 | } 75 | 76 | // All okay, so pass to subclass for handling: 77 | return onExecute(verb, parameter, missionInit); 78 | } 79 | 80 | protected void setUpAllowAndDenyLists(CommandListModifier list) 81 | { 82 | this.commandsDenyList = null; 83 | this.commandsAllowList = null; 84 | if (list != null && list.getCommand() != null) 85 | { 86 | ArrayList listcopy = new ArrayList(); 87 | listcopy.addAll(list.getCommand()); 88 | if (list.getType().equalsIgnoreCase("deny-list")) 89 | this.commandsDenyList = listcopy; 90 | else 91 | this.commandsAllowList = listcopy; 92 | } 93 | } 94 | 95 | abstract protected boolean onExecute(String verb, String parameter, MissionInit missionInit); 96 | } --------------------------------------------------------------------------------