diff --git a/default_launch.json b/default_launch.json index f5acc67..79d73f9 100644 --- a/default_launch.json +++ b/default_launch.json @@ -20,6 +20,15 @@ "options": { "manual_worker_connection_only": true } + }, + { + "layer": "entity_worker", + "hex_grid": { + "num_workers": 1 + }, + "options": { + "manual_worker_connection_only": true + } } ] }, @@ -47,6 +56,14 @@ "all": {} } ] + }, + { + "worker_type": "EntityWorker", + "permissions": [ + { + "all": {} + } + ] } ] } diff --git a/schema/components/bootstrap.schema b/schema/components/bootstrap.schema new file mode 100644 index 0000000..7094fa7 --- /dev/null +++ b/schema/components/bootstrap.schema @@ -0,0 +1,22 @@ +package minecraft.boostrap; + +import "components/player.schema"; +import "components/general.schema"; +import "components/world.schema"; + +// Reserves 1400-1449 + +type Message { + string message = 1; +} + +/** + * A single chunk holds 16x16x16 states. + */ +component Bootstrap { + id = 1400; + map online_players = 1; + map state_registry = 2; + command minecraft.general.Void on_chat(Message); + event Message on_message; +} \ No newline at end of file diff --git a/schema/components/entity.schema b/schema/components/entity.schema index 9d4713c..e1eda68 100644 --- a/schema/components/entity.schema +++ b/schema/components/entity.schema @@ -1,5 +1,7 @@ package minecraft.entity; import "improbable/standard_library.schema"; +import "improbable/vector3.schema"; +import "components/general.schema"; // Reserves 1000-1099 @@ -28,18 +30,11 @@ component Rotation { component Motion { id = 1005; - improbable.Coordinates coords = 1; + improbable.Vector3f motion = 1; } -type GameProfile { - string uuid = 1; -} - -component Player { - id = 1006; - GameProfile profile = 1; - bool sneaking = 2; - bool sprinting = 3; +component WorldEntity { + id= 1010; } component ChatAbility { @@ -50,10 +45,8 @@ type IgnitionRequest { int32 time = 1; } -type Void {} - component Flammable { id = 1008; bool is_on_fire = 1; - command Void ignite(IgnitionRequest); + command minecraft.general.Void ignite(IgnitionRequest); } \ No newline at end of file diff --git a/schema/components/general.schema b/schema/components/general.schema new file mode 100644 index 0000000..140dc82 --- /dev/null +++ b/schema/components/general.schema @@ -0,0 +1,3 @@ +package minecraft.general; + +type Void {} \ No newline at end of file diff --git a/schema/components/player.schema b/schema/components/player.schema new file mode 100644 index 0000000..6e361d6 --- /dev/null +++ b/schema/components/player.schema @@ -0,0 +1,43 @@ +package minecraft.player; + +import "improbable/vector3.schema"; +import "components/general.schema"; + +// Reserves 1450-1499 + +type GameProfile { + string uuid = 1; + string name = 2; +} + +component PlayerInfo { + id = 1450; + GameProfile profile = 1; +} + +component MapRepresentation { + id = 1453; + uint32 colour = 1; + string icon = 2; +} + +type Hand { + bool main = 1; +} + +component PlayerInput { + id = 1451; + improbable.Vector3f move_position = 1; + improbable.Vector3f desired_motion = 2; + bool sprinting = 3; + bool sneaking = 4; + command minecraft.general.Void item_rightclick(Hand); +} + +type Heartbeat { +} + +component PlayerConnection { + id = 1452; + event Heartbeat heartbeat; +} \ No newline at end of file diff --git a/spatialos.json b/spatialos.json index 944696d..66cbae0 100644 --- a/spatialos.json +++ b/spatialos.json @@ -1,8 +1,8 @@ { "name": "spatial", "project_version": "0.0.1", - "sdk_version": "13.5.0", + "sdk_version": "13.6.1", "dependencies": [ - {"name": "standard_library", "version": "13.5.0"} + {"name": "standard_library", "version": "13.6.1"} ] } diff --git a/workers/java/settings.gradle b/workers/java/settings.gradle index c33b5cf..de55a70 100644 --- a/workers/java/settings.gradle +++ b/workers/java/settings.gradle @@ -3,4 +3,4 @@ include 'worker-sdk' include 'worker:patcherdummy' rootProject.name = "HorizonJavaWorker" -gradle.ext.mainClass = 'com.hrznstudio.spatial.SpatialLaunchWrapper' \ No newline at end of file +gradle.ext.mainClass = 'com.hrznstudio.spatial.launch.SpatialLaunchWrapper' \ No newline at end of file diff --git a/workers/java/spatialos.Bootstrapper.worker.json b/workers/java/spatialos.Bootstrapper.worker.json new file mode 100644 index 0000000..578f381 --- /dev/null +++ b/workers/java/spatialos.Bootstrapper.worker.json @@ -0,0 +1,54 @@ +{ + "build": { + "tasks_filename": "spatialos.java.build.json" + }, + "bridge": { + "worker_attribute_set": { + "attributes": [ + "bootstrap" + ] + }, + "entity_interest": { + "range_entity_interest": { + "radius": 0 + } + }, + "streaming_query": [], + "component_delivery": { + "default": "RELIABLE_ORDERED", + "checkout_all_initially": true + } + }, + "external": { + "default": { + "run_type": "EXECUTABLE_ZIP", + "linux": { + "artifact_name": "HorizonJavaWorker@Linux.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "Bootstrapper" + ] + }, + "windows": { + "artifact_name": "HorizonJavaWorker@Windows.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "Bootstrapper" + ] + }, + "macos": { + "artifact_name": "HorizonJavaWorker@Mac.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "Bootstrapper" + ] + } + } + } +} \ No newline at end of file diff --git a/workers/java/spatialos.EntityWorker.worker.json b/workers/java/spatialos.EntityWorker.worker.json new file mode 100644 index 0000000..5357895 --- /dev/null +++ b/workers/java/spatialos.EntityWorker.worker.json @@ -0,0 +1,54 @@ +{ + "build": { + "tasks_filename": "spatialos.java.build.json" + }, + "bridge": { + "worker_attribute_set": { + "attributes": [ + "entity_worker" + ] + }, + "entity_interest": { + "range_entity_interest": { + "radius": 0 + } + }, + "streaming_query": [], + "component_delivery": { + "default": "RELIABLE_ORDERED", + "checkout_all_initially": true + } + }, + "external": { + "default": { + "run_type": "EXECUTABLE_ZIP", + "linux": { + "artifact_name": "HorizonJavaWorker@Linux.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "EntityWorker" + ] + }, + "windows": { + "artifact_name": "HorizonJavaWorker@Windows.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "EntityWorker" + ] + }, + "macos": { + "artifact_name": "HorizonJavaWorker@Mac.zip", + "command": "java", + "arguments": [ + "-jar", + "HorizonJavaWorker.jar", + "EntityWorker" + ] + } + } + } +} \ No newline at end of file diff --git a/workers/java/spatialos.HorizonClientWorker.worker.json b/workers/java/spatialos.HorizonClientWorker.worker.json index f48e751..6555a7a 100644 --- a/workers/java/spatialos.HorizonClientWorker.worker.json +++ b/workers/java/spatialos.HorizonClientWorker.worker.json @@ -4,11 +4,13 @@ }, "bridge": { "worker_attribute_set": { - "attributes": [] + "attributes": [ + "horizon_client" + ] }, "entity_interest": { "range_entity_interest": { - "radius": 10 + "radius": 128 } }, "streaming_query": [], diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialLaunchWrapper.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialLaunchWrapper.java deleted file mode 100644 index 1fe2952..0000000 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialLaunchWrapper.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.hrznstudio.spatial; - -import net.minecraft.launchwrapper.Launch; -import org.apache.commons.lang3.ArrayUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; - -public final class SpatialLaunchWrapper { - - private SpatialLaunchWrapper() { - } - - public static void main(String[] args) { - setEnvironment(); - Launch.main(ArrayUtils.addAll(args, - "--tweakClass", - SpatialTweaker.class.getName(), - "--tweakClass", - "net.minecraftforge.fml.common.launcher.FMLTweaker", -// "net.minecraftforge.fml.common.launcher.FMLServerTweaker", - "--tweakClass", - "net.minecraftforge.gradle.tweakers.CoremodTweaker" - )); - } - - private static void setEnvironment() { - try { - Class gradleStart = Class.forName("net.minecraftforge.gradle.GradleStartCommon"); - - System.setProperty("net.minecraftforge.gradle.GradleStart.srg.notch-srg", getStaticFile(gradleStart, "SRG_NOTCH_SRG").getCanonicalPath()); - System.setProperty("net.minecraftforge.gradle.GradleStart.srg.notch-mcp", getStaticFile(gradleStart, "SRG_NOTCH_MCP").getCanonicalPath()); - System.setProperty("net.minecraftforge.gradle.GradleStart.srg.srg-mcp", getStaticFile(gradleStart, "SRG_SRG_MCP").getCanonicalPath()); - System.setProperty("net.minecraftforge.gradle.GradleStart.srg.mcp-srg", getStaticFile(gradleStart, "SRG_MCP_SRG").getCanonicalPath()); - System.setProperty("net.minecraftforge.gradle.GradleStart.srg.mcp-notch", getStaticFile(gradleStart, "SRG_MCP_NOTCH").getCanonicalPath()); - System.setProperty("net.minecraftforge.gradle.GradleStart.csvDir", getStaticFile(gradleStart, "CSV_DIR").getCanonicalPath()); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | IOException ignored) { - // Not in dev environment - } - } - - private static File getStaticFile(final Class clazz, final String field) throws NoSuchFieldException, IllegalAccessException { - Field f = clazz.getDeclaredField(field); - f.setAccessible(true); - return (File) f.get(null); - } - -} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialMod.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialMod.java index ace038e..3e45561 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialMod.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialMod.java @@ -1,27 +1,17 @@ package com.hrznstudio.spatial; import com.hrznstudio.spatial.client.GuiConnecting; +import com.hrznstudio.spatial.client.GuiExpanseMenu; import com.hrznstudio.spatial.client.HorizonClientWorker; -import com.hrznstudio.spatial.util.CommonWorkerRequirements; -import com.hrznstudio.spatial.util.EntityBuilder; -import improbable.Coordinates; -import improbable.Position; -import improbable.PositionData; -import improbable.worker.Entity; -import minecraft.entity.*; -import minecraft.inventory.Inventory; -import minecraft.inventory.InventoryData; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiMainMenu; +import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLServerStartingEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.util.Collections; -import java.util.UUID; - -@Mod(modid = "spatial", name = "Spatial", version = "0.0.1") +@Mod(modid = "expanse", name = "Expanse", version = "0.0.1") @Mod.EventBusSubscriber public class SpatialMod { @@ -41,47 +31,14 @@ public static void actionEvent(GuiScreenEvent.ActionPerformedEvent.Pre event) { } } - @Mod.EventHandler - public void serverStarting(FMLServerStartingEvent event) { + @SubscribeEvent + public static void initGuiEvent(GuiOpenEvent event) { + if (event.getGui() instanceof GuiMainMenu&&!(event.getGui() instanceof GuiExpanseMenu)) { + event.setGui(new GuiExpanseMenu()); + } } - public static Entity createPlayerEntity() { - EntityBuilder builder = new EntityBuilder("Player"); - builder.addComponent( - Position.COMPONENT, - new PositionData(new Coordinates(0, 0, 0)), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Player.COMPONENT, - new PlayerData(new GameProfile(UUID.randomUUID().toString()), false, false), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Health.COMPONENT, - new HealthData(20, 20), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Food.COMPONENT, - new FoodData(20, 20), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Experience.COMPONENT, - new ExperienceData(0), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Inventory.COMPONENT, - new InventoryData(Collections.emptyMap()), - CommonWorkerRequirements.getEntityWorkers() - ); - builder.addComponent( - Flammable.COMPONENT, - new FlammableData(false), - CommonWorkerRequirements.getEntityWorkers() - ); - return builder.build(); + @Mod.EventHandler + public void serverStarting(FMLServerStartingEvent event) { } -} +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialTweaker.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialTweaker.java deleted file mode 100644 index b62fbde..0000000 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/SpatialTweaker.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.hrznstudio.spatial; - -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.apache.commons.lang3.ArrayUtils; - -import java.io.File; -import java.util.List; - -public final class SpatialTweaker implements ITweaker { - private String[] args; - - @Override - public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { - } - - @Override - public void injectIntoClassLoader(LaunchClassLoader classLoader) { - } - - @Override - public String getLaunchTarget() { - return "com.hrznstudio.spatial.WorkerManager"; - } - - @Override - public String[] getLaunchArguments() { - return ArrayUtils.EMPTY_STRING_ARRAY; - } -} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerManager.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerManager.java deleted file mode 100644 index cc73274..0000000 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerManager.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.hrznstudio.spatial; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import picocli.CommandLine; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -@CommandLine.Command(name = "worker", sortOptions = false, - - header = { - "@|blue Spatial Worker Manager |@", - "" - }, - descriptionHeading = "@|bold %nDescription|@:%n", - description = { - "Displays commands and usage help.", - } -) -public class WorkerManager implements Runnable { - - @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Displays commands and usage help.") - private boolean help; - - @CommandLine.Parameters(description = "Worker to run") - private String worker; - - public static Map workerMap = new HashMap<>(); - - private static Logger logger = LogManager.getLogger(WorkerManager.class.getSimpleName()); - - public static void main(String... args) { - int i = ArrayUtils.indexOf(args, "--version"); - if (i != ArrayUtils.INDEX_NOT_FOUND) { - args = ArrayUtils.subarray(args, 0, i); - } else - logger.warn("Running the WorkerManager directly is not recommended. Please use SpatialLaunchWrapper instead."); - ServiceLoader workerService = ServiceLoader.load(WorkerService.class); - workerService.forEach(service -> workerMap.put(service.getWorkerID(), service)); - - CommandLine.run(new WorkerManager(), System.out, args); - } - - @Override - public void run() { - if(workerMap.containsKey(worker)) { - workerMap.get(worker).start(); - } - } -} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerService.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerService.java deleted file mode 100644 index 5254324..0000000 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/WorkerService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.hrznstudio.spatial; - -public interface WorkerService { - String getWorkerID(); - - void start(); -} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/IDispatcherLoop.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/IDispatcherLoop.java new file mode 100644 index 0000000..5f48b0b --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/IDispatcherLoop.java @@ -0,0 +1,5 @@ +package com.hrznstudio.spatial.api; + +public interface IDispatcherLoop { + void onLoop(); +} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialEntity.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialEntity.java new file mode 100644 index 0000000..464eec8 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialEntity.java @@ -0,0 +1,8 @@ +package com.hrznstudio.spatial.api; + +import improbable.worker.EntityId; + +public interface ISpatialEntity { + EntityId getSpatialId(); + void setSpatialId(EntityId id); +} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialWorld.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialWorld.java new file mode 100644 index 0000000..3b1efa4 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/api/ISpatialWorld.java @@ -0,0 +1,10 @@ +package com.hrznstudio.spatial.api; + +import improbable.worker.EntityId; +import net.minecraft.entity.Entity; + +public interface ISpatialWorld { + Entity getEntityById(EntityId id); + void addSpatial(Entity entity); + void removeSpatial(Entity entity); +} diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/ClientView.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/ClientView.java index acaa7b4..e1c4232 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/ClientView.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/ClientView.java @@ -2,55 +2,190 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import com.hrznstudio.spatial.SpatialMod; +import com.hrznstudio.spatial.api.IDispatcherLoop; +import com.hrznstudio.spatial.api.ISpatialEntity; +import com.hrznstudio.spatial.api.ISpatialWorld; import com.hrznstudio.spatial.client.vanillawrappers.WorldClientSpatial; +import com.hrznstudio.spatial.util.ConnectionManager; import com.hrznstudio.spatial.util.Converters; +import com.hrznstudio.spatial.util.EntityRequirementCallback; +import com.hrznstudio.spatial.util.Util; import com.hrznstudio.spatial.worker.chunk.ChunkWorker; -import improbable.Metadata; -import improbable.MetadataData; +import com.mojang.authlib.GameProfile; +import improbable.Coordinates; import improbable.Position; -import improbable.PositionData; -import improbable.collections.Option; +import improbable.Vector3f; import improbable.worker.Entity; import improbable.worker.EntityId; import improbable.worker.View; +import minecraft.entity.*; +import minecraft.player.*; import minecraft.world.ChunkStorage; import minecraft.world.ChunkStorageData; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityOtherPlayerMP; +import net.minecraft.client.gui.GuiIngame; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.entity.EntityTracker; +import net.minecraft.server.management.PlayerList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3i; -public class ClientView extends View { +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ClientView extends View implements IDispatcherLoop { private final ChunkStorageData empty = ChunkStorageData.create(); private final BiMap posToIdChunks = HashBiMap.create(); private final BiMap idToPosChunks = posToIdChunks.inverse(); + public final List players = new ArrayList<>(); + + @Override + public void onLoop() { + if (SpatialMod.getClientWorker().getPlayerId() != null) + ConnectionManager.getConnection().sendComponentUpdate(PlayerConnection.COMPONENT, SpatialMod.getClientWorker().getPlayerId(), new PlayerConnection.Update().addHeartbeat(new Heartbeat())); + } public ClientView() { - this.onRemoveEntity(op -> removeChunk(op.entityId)); - // TODO: abstract away some system to require several components and listen to all of them - // TODO: listen to chunk content updates - this.onAddComponent(Position.COMPONENT, op -> { - final BlockPos chunkPos = Converters.improbableToChunkPos(op.data); - final Option meta = ClientView.this.entities.get(op.entityId).get(Metadata.COMPONENT); - if (meta.isPresent() && meta.get().getEntityType().equals(ChunkWorker.CHUNK)) - addChunk(chunkPos, op.entityId); - final Option storage = ClientView.this.entities.get(op.entityId).get(ChunkStorage.COMPONENT); - if (storage.isPresent()) - ((WorldClientSpatial) Minecraft.getMinecraft().world).loadChunk(chunkPos, storage.get()); + this.onRemoveEntity(op -> removeEntity(op.entityId)); + EntityRequirementCallback.builder( + (id) -> { + Entity entity = getEntity(id); + BlockPos pos = Converters.improbableToChunkPos(Util.getData(entity, Position.COMPONENT)); + addChunk(pos, id); + ((WorldClientSpatial) Minecraft.getMinecraft().world).loadChunk(pos, Util.getData(entity, ChunkStorage.COMPONENT)); + }) + .requireType(ChunkWorker.CHUNK) + .requireComponent(Position.COMPONENT) + .requireComponent(ChunkStorage.COMPONENT) + .attach(this); + EntityRequirementCallback.builder( + (id) -> { + if (id == SpatialMod.getClientWorker().getPlayerId()) + return; + WorldClient world = Minecraft.getMinecraft().world; + if (world == null) { + players.add(id); //TODO: Figure out when best to load these players who get sent before world load + } else { + Entity entity = getEntity(id); + Coordinates pos = Util.getData(entity, Position.COMPONENT).getCoords(); + PlayerInfoData player = Util.getData(entity, PlayerInfo.COMPONENT); + RotationData rotation = Util.getData(entity, Rotation.COMPONENT); + GameProfile profile = new GameProfile(UUID.fromString(player.getProfile().getUuid()), player.getProfile().getName()); + EntityOtherPlayerMP mp = new EntityOtherPlayerMP(world, profile); + double d0 = pos.getX(); + double d1 = pos.getY(); + double d2 = pos.getZ(); + float f = (rotation.getYaw() * 360) / 256.0F; + float f1 = (rotation.getPitch() * 360) / 256.0F; + mp.prevPosX = d0; + mp.lastTickPosX = d0; + mp.prevPosY = d1; + mp.lastTickPosY = d1; + mp.prevPosZ = d2; + mp.lastTickPosZ = d2; + EntityTracker.updateServerPosition(mp, d0, d1, d2); + mp.setPositionAndRotation(d0, d1, d2, f, f1); + ((ISpatialEntity) mp).setSpatialId(id); + world.addEntityToWorld(mp.getEntityId(), mp); + } + }) + .requireType("Player") + .requireComponent(PlayerInfo.COMPONENT) + .requireComponent(Position.COMPONENT) + .attach(this); + onComponentUpdate(Position.COMPONENT, argument -> { + if (Util.getType(entities.get(argument.entityId)).equals("Player")) { + Coordinates coords = argument.update.getCoords().orElse(null); + if (coords != null) { + Minecraft.getMinecraft().addScheduledTask(() -> { + WorldClient world = Minecraft.getMinecraft().world; + if (world == null) + return; + if (argument.entityId.equals(SpatialMod.getClientWorker().getPlayerId())) { + double dist = 0.5; + boolean x = Util.isWithin(Minecraft.getMinecraft().player.posX, coords.getX(), dist); + boolean y = Util.isWithin(Minecraft.getMinecraft().player.posY, coords.getY(), dist); + boolean z = Util.isWithin(Minecraft.getMinecraft().player.posZ, coords.getZ(), dist); + if (!x && !y && !z) { + net.minecraft.entity.Entity entity = Minecraft.getMinecraft().player; + if (entity != null) + entity.setPositionAndUpdate(coords.getX(), coords.getY(), coords.getZ()); + } + } else { + net.minecraft.entity.Entity entity = ((ISpatialWorld) world).getEntityById(argument.entityId); + if (entity != null) + entity.setPositionAndUpdate(coords.getX(), coords.getY(), coords.getZ()); + } + }); + } + } }); - this.onAddComponent(Metadata.COMPONENT, op -> { - if (op.data.getEntityType().equals(ChunkWorker.CHUNK)) { - final Option pos = ClientView.this.entities.get(op.entityId).get(Position.COMPONENT); - if (pos.isPresent()) addChunk(Converters.improbableToChunkPos(pos.get()), op.entityId); + onComponentUpdate(Rotation.COMPONENT, argument -> { + if (Util.getType(entities.get(argument.entityId)).equals("Player")) { + if (argument.entityId.equals(SpatialMod.getClientWorker().getPlayerId())) + return; + Float pitch = argument.update.getPitch().orElse(null); + Float yaw = argument.update.getYaw().orElse(null); + if (yaw != null || pitch != null) { + Minecraft.getMinecraft().addScheduledTask(() -> { + WorldClient world = Minecraft.getMinecraft().world; + if (world == null) + return; + net.minecraft.entity.Entity entity = ((ISpatialWorld) world).getEntityById(argument.entityId); + if (entity != null) + entity.setPositionAndRotation(entity.posX, entity.posY, entity.posZ, pitch == null ? entity.rotationPitch : pitch, yaw == null ? entity.rotationYaw : yaw); + }); + } } }); - this.onAddComponent(ChunkStorage.COMPONENT, op -> { - final Option pos = ClientView.this.entities.get(op.entityId).get(Position.COMPONENT); - if (pos.isPresent()) - ((WorldClientSpatial) Minecraft.getMinecraft().world).loadChunk(Converters.improbableToChunkPos(pos.get()), op.data); + onComponentUpdate(Motion.COMPONENT, argument -> { + if (Util.getType(entities.get(argument.entityId)).equals("Player")) { + if (argument.entityId.equals(SpatialMod.getClientWorker().getPlayerId())) + return; + Vector3f motion = argument.update.getMotion().orElse(null); + if (motion != null) { + Minecraft.getMinecraft().addScheduledTask(() -> { + WorldClient world = Minecraft.getMinecraft().world; + if (world == null) + return; + net.minecraft.entity.Entity entity = ((ISpatialWorld) world).getEntityById(argument.entityId); + if (entity != null) { + entity.motionX = motion.getX(); + entity.motionY = motion.getY(); + entity.motionZ = motion.getZ(); + } + }); + } + } }); } + @Nullable + public Entity getEntity(EntityId id) { + return entities.get(id); + } + + private void removeEntity(EntityId id) { + String type = Util.getType(getEntity(id)); + if (type.equals(ChunkWorker.CHUNK)) + removeChunk(id); + else if (type.equals("Player")) { + removePlayer(id); + } + } + + private void removePlayer(EntityId player) { + players.remove(player); + if (Minecraft.getMinecraft().world != null) { + Minecraft.getMinecraft().world.removeEntity(((ISpatialWorld) Minecraft.getMinecraft().world).getEntityById(player)); + } + } + private void removeChunk(EntityId chunk) { BlockPos pos = idToPosChunks.remove(chunk); if (pos != null) ((WorldClientSpatial) Minecraft.getMinecraft().world).unloadChunk(pos); @@ -67,7 +202,7 @@ private void addChunk(BlockPos pos, EntityId chunk) { public ChunkStorageData getChunk(final BlockPos pos) { EntityId id = posToIdChunks.get(pos); if (id == null) return empty; - Entity entity = entities.get(id); + Entity entity = getEntity(id); if (entity == null) return empty; return entity.get(ChunkStorage.COMPONENT).orElse(empty); } diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/GuiExpanseMenu.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/GuiExpanseMenu.java new file mode 100644 index 0000000..b30f592 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/GuiExpanseMenu.java @@ -0,0 +1,87 @@ +package com.hrznstudio.spatial.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiButtonLanguage; +import net.minecraft.client.gui.GuiLabel; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.common.Loader; +import org.lwjgl.input.Mouse; + +public class GuiExpanseMenu extends GuiMainMenu { + @Override + public void initGui() { + this.viewportTexture = new DynamicTexture(256, 256); + this.backgroundTexture = this.mc.getTextureManager().getDynamicTextureLocation("background", this.viewportTexture); + this.widthCopyright = this.fontRenderer.getStringWidth("Copyright Mojang AB. Do not distribute!"); + this.widthCopyrightRest = this.width - this.widthCopyright - 2; + + int buttonGap = 24; + int yPos = this.height / 4 + 48; + + this.buttonList.add(new GuiButton(2, this.width / 2 - 100, yPos, "Connect to Expanse")); + GuiButton extensions = new GuiButton(6, this.width / 2 - 100, yPos + buttonGap, "Extensions"); + extensions.enabled = false; + this.buttonList.add(extensions); + + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, yPos + 72, 98, 20, I18n.format("menu.options"))); + this.buttonList.add(new GuiButton(4, this.width / 2 + 2, yPos + 72, 98, 20, I18n.format("menu.quit"))); + this.buttonList.add(new GuiButtonLanguage(5, this.width / 2 - 124, yPos + 72)); + + synchronized (this.threadLock) { + this.openGLWarning1Width = this.fontRenderer.getStringWidth(this.openGLWarning1); + this.openGLWarning2Width = this.fontRenderer.getStringWidth(this.openGLWarning2); + int k = Math.max(this.openGLWarning1Width, this.openGLWarning2Width); + this.openGLWarningX1 = (this.width - k) / 2; + this.openGLWarningY1 = (this.buttonList.get(0)).y - 24; + this.openGLWarningX2 = this.openGLWarningX1 + k; + this.openGLWarningY2 = this.openGLWarningY1 + 24; + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + this.panoramaTimer += partialTicks; + GlStateManager.disableAlpha(); + this.renderSkybox(mouseX, mouseY, partialTicks); + GlStateManager.enableAlpha(); + int xPos = this.width / 2 - 137; + this.drawGradientRect(0, 0, this.width, this.height, -2130706433, 16777215); + this.drawGradientRect(0, 0, this.width, this.height, 0, Integer.MIN_VALUE); + this.mc.getTextureManager().bindTexture(MINECRAFT_TITLE_TEXTURES); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + this.drawTexturedModalRect(xPos, 30, 0, 0, 155, 44); + this.drawTexturedModalRect(xPos + 155, 30, 0, 45, 155, 44); + + this.mc.getTextureManager().bindTexture(field_194400_H); + drawModalRectWithCustomSizedTexture(width / 2 - 63, 67, 0.0F, 0.0F, 126, 14, 128, 16.0F); + + String minecraftVersion = "Minecraft " + Loader.MC_VERSION; + this.drawString(this.fontRenderer, minecraftVersion, 2, this.height - 10, 16777215); + + this.drawString(this.fontRenderer, "Copyright Mojang AB. Do not distribute!", this.widthCopyrightRest, this.height - 10, -1); + + if (mouseX > this.widthCopyrightRest && mouseX < this.widthCopyrightRest + this.widthCopyright && mouseY > this.height - 10 && mouseY < this.height && Mouse.isInsideWindow()) { + drawRect(this.widthCopyrightRest, this.height - 1, this.widthCopyrightRest + this.widthCopyright, this.height, -1); + } + + if (this.openGLWarning1 != null && !this.openGLWarning1.isEmpty()) { + drawRect(this.openGLWarningX1 - 2, this.openGLWarningY1 - 2, this.openGLWarningX2 + 2, this.openGLWarningY2 - 1, 1428160512); + this.drawString(this.fontRenderer, this.openGLWarning1, this.openGLWarningX1, this.openGLWarningY1, -1); + this.drawString(this.fontRenderer, this.openGLWarning2, (this.width - this.openGLWarning2Width) / 2, (this.buttonList.get(0)).y - 12, -1); + } + + for (GuiButton button : this.buttonList) { + button.drawButton(this.mc, mouseX, mouseY, partialTicks); + } + + for (GuiLabel label : this.labelList) { + label.drawLabel(this.mc, mouseX, mouseY); + } + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/HorizonClientWorker.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/HorizonClientWorker.java index c3b5cdb..0ad41a8 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/HorizonClientWorker.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/HorizonClientWorker.java @@ -1,21 +1,20 @@ package com.hrznstudio.spatial.client; import com.hrznstudio.spatial.client.vanillawrappers.SpatialNetworkManager; +import com.hrznstudio.spatial.util.CommonWorkerRequirements; import com.hrznstudio.spatial.util.ConnectionManager; import com.hrznstudio.spatial.util.ConnectionStatus; import com.hrznstudio.spatial.util.EntityBuilder; import com.hrznstudio.spatial.worker.BaseWorker; -import improbable.Coordinates; -import improbable.Position; -import improbable.WorkerAttributeSet; -import improbable.WorkerRequirementSet; +import improbable.*; import improbable.collections.Option; import improbable.worker.*; +import minecraft.entity.*; +import minecraft.player.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketJoinGame; import net.minecraft.network.play.server.SPacketPlayerPosLook; @@ -26,11 +25,12 @@ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; public final class HorizonClientWorker extends BaseWorker { - private EntityId playerId; + private volatile EntityId playerId; private NetHandlerPlayClient netHandlerPlayClient; private NetworkManager networkManager; private GuiMainMenu guiMainMenu; @@ -39,6 +39,7 @@ public HorizonClientWorker() { super(ClientView::new); } + @Nullable public EntityId getPlayerId() { return playerId; } @@ -76,37 +77,72 @@ protected void onConnected() { dispatcher.onReserveEntityIdsResponse(op -> { if (op.requestId.equals(entityIdReservationRequestId) && op.statusCode == StatusCode.SUCCESS) { EntityBuilder builder = new EntityBuilder("Player"); - builder.addComponent(Position.COMPONENT, new improbable.PositionData(new Coordinates(5, 200, 5)), // TODO: use position from server + builder.addComponent(Position.COMPONENT, new improbable.PositionData(new Coordinates(8, 20, 8)), // TODO: use position from server + CommonWorkerRequirements.createWorkerRequirementSet("entity_worker") + ); + builder.addComponent( + PlayerInfo.COMPONENT, + new PlayerInfoData(new GameProfile( + Minecraft.getMinecraft().getSession().getPlayerID(), Minecraft.getMinecraft().getSession().getUsername() + ) + ), + CommonWorkerRequirements.createWorkerRequirementSet("entity_worker") + ); + builder.addComponent( + PlayerInput.COMPONENT, + new PlayerInputData(new Vector3f(0, 0, 0),new Vector3f(0, 0, 0), false, false + ), + new WorkerRequirementSet(Collections.singletonList(new WorkerAttributeSet(Collections.singletonList("workerId:" + this.getName())))) + ); + builder.addComponent( + PlayerConnection.COMPONENT, + new PlayerConnectionData(), new WorkerRequirementSet(Collections.singletonList(new WorkerAttributeSet(Collections.singletonList("workerId:" + this.getName())))) ); + builder.addComponent( + Motion.COMPONENT, + new MotionData(new Vector3f(0, 0, 0)), + CommonWorkerRequirements.createWorkerRequirementSet("entity_worker") + ); + builder.addComponent( + Rotation.COMPONENT, + new RotationData(0, 0), + new WorkerRequirementSet(Collections.singletonList(new WorkerAttributeSet(Collections.singletonList("workerId:" + this.getName())))) + ); + builder.addComponent( + WorldEntity.COMPONENT, + new WorldEntityData(), + CommonWorkerRequirements.createWorkerRequirementSet("entity_worker") + ); createEntityRequestRequestId.set(connection.sendCreateEntityRequest(builder.build(), op.firstEntityId, timeoutMillis)); } }); + Minecraft mc = Minecraft.getMinecraft(); dispatcher.onCreateEntityResponse(argument -> { if (argument.requestId.equals(createEntityRequestRequestId.get()) && argument.statusCode == StatusCode.SUCCESS) { playerId = argument.entityId.get(); + } else { + stop(); } }); - - Minecraft mc = Minecraft.getMinecraft(); - networkManager = new SpatialNetworkManager(this); - netHandlerPlayClient = new NetHandlerPlayClient(mc, guiMainMenu, networkManager, mc.getSession().getProfile()); - FMLClientHandler.instance().setPlayClient(netHandlerPlayClient); - NetworkDispatcher.allocAndSet(networkManager); - mc.addScheduledTask(() -> { + networkManager = new SpatialNetworkManager(this); + netHandlerPlayClient = new NetHandlerPlayClient(mc, guiMainMenu, networkManager, mc.getSession().getProfile()); + FMLClientHandler.instance().setPlayClient(netHandlerPlayClient); + NetworkDispatcher.allocAndSet(networkManager); + networkManager.setNetHandler(netHandlerPlayClient); netHandlerPlayClient.handleJoinGame(new SPacketJoinGame( 0, GameType.CREATIVE, false, 0, EnumDifficulty.NORMAL, - 9001, + 1000, WorldType.FLAT, false )); netHandlerPlayClient.handlePlayerPosLook(new SPacketPlayerPosLook( - 5, 60, 5, 0, 0, Collections.emptySet(), -1 + 8, 60, 8, 0, 0, Collections.emptySet(), -1 )); // TODO: use position from server }); } @@ -116,6 +152,13 @@ protected void onDisConnected(@Nonnull final Ops.Disconnect reason) { super.onDisConnected(reason); WorldClient wc = Minecraft.getMinecraft().world; if (wc != null) wc.sendQuittingDisconnectingPacket(); - // TODO: remove player entity + } + + public NetHandlerPlayClient getNetHandlerPlayClient() { + return netHandlerPlayClient; + } + + public NetworkManager getNetworkManager() { + return networkManager; } } diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialNetworkManager.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialNetworkManager.java index 2783eef..53a3d38 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialNetworkManager.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialNetworkManager.java @@ -1,11 +1,18 @@ package com.hrznstudio.spatial.client.vanillawrappers; +import com.hrznstudio.spatial.SpatialMod; import com.hrznstudio.spatial.client.HorizonClientWorker; +import com.hrznstudio.spatial.util.ConnectionManager; +import improbable.collections.Option; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; +import minecraft.player.Hand; +import minecraft.player.PlayerInput; import net.minecraft.network.*; +import net.minecraft.network.play.client.CPacketPlayerTryUseItem; +import net.minecraft.util.EnumHand; import net.minecraft.util.text.ITextComponent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,7 +30,7 @@ public SpatialNetworkManager(HorizonClientWorker clientWorker) { } @Override - public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception { + public void channelActive(ChannelHandlerContext p_channelActive_1_) { logger.info(() -> "SpatialNetworkManager#channelActive not implemented"); } @@ -33,17 +40,17 @@ public void setConnectionState(EnumConnectionState newState) { } @Override - public void channelInactive(ChannelHandlerContext p_channelInactive_1_) throws Exception { + public void channelInactive(ChannelHandlerContext p_channelInactive_1_) { logger.info(() -> "SpatialNetworkManager#channelInactive not implemented"); } @Override - public void exceptionCaught(ChannelHandlerContext p_exceptionCaught_1_, Throwable p_exceptionCaught_2_) throws Exception { + public void exceptionCaught(ChannelHandlerContext p_exceptionCaught_1_, Throwable p_exceptionCaught_2_) { logger.info(() -> "SpatialNetworkManager#exceptionCaught not implemented"); } @Override - protected void channelRead0(ChannelHandlerContext p_channelRead0_1_, Packet p_channelRead0_2_) throws Exception { + protected void channelRead0(ChannelHandlerContext p_channelRead0_1_, Packet p_channelRead0_2_) { logger.info(() -> "SpatialNetworkManager#channelRead0 not implemented"); } @@ -54,7 +61,13 @@ public void setNetHandler(INetHandler handler) { @Override public void sendPacket(Packet packetIn) { - logger.info(() -> "SpatialNetworkManager#sendPacket not implemented (received " + packetIn.getClass() + ")"); + if (packetIn instanceof CPacketPlayerTryUseItem) { + Hand hand = Hand.create(); + hand.setMain(((CPacketPlayerTryUseItem) packetIn).getHand() == EnumHand.MAIN_HAND); + ConnectionManager.getConnection().sendCommandRequest(PlayerInput.Commands.ITEM_RIGHTCLICK, SpatialMod.getClientWorker().getPlayerId(), hand, Option.empty()); + } else { + logger.info(() -> "SpatialNetworkManager#sendPacket not implemented for received packet (" + packetIn.getClass() + ")"); + } } @Override diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialPrimer.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialPrimer.java new file mode 100644 index 0000000..d439143 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/client/vanillawrappers/SpatialPrimer.java @@ -0,0 +1,26 @@ +package com.hrznstudio.spatial.client.vanillawrappers; + +import com.hrznstudio.spatial.SpatialMod; +import com.hrznstudio.spatial.client.ClientView; +import com.hrznstudio.spatial.util.Converters; +import minecraft.world.ChunkStorageData; +import minecraft.world.State; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.world.chunk.ChunkPrimer; + +public class SpatialPrimer extends ChunkPrimer { + @Override + public IBlockState getBlockState(int x, int y, int z) { + final ClientView view = SpatialMod.getClientWorker().getDispatcher(); + if (view == null) return Blocks.AIR.getDefaultState(); + final ChunkStorageData chunk = view.getChunkFromBlock(x, y, z); + if (chunk == null) return Blocks.AIR.getDefaultState(); + final State state = chunk.getBlocks().get(Converters.blockPosToChunkIndex(x, y, z)); + if (state == null) return Blocks.AIR.getDefaultState(); + final net.minecraft.block.Block block = net.minecraft.block.Block.getBlockFromName(state.getBlock().getId()); + if (block == null) return Blocks.AIR.getDefaultState(); + //noinspection deprecation + return block.getStateFromMeta(state.getMeta()); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntity.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntity.java new file mode 100644 index 0000000..0134cd1 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntity.java @@ -0,0 +1,30 @@ +package com.hrznstudio.spatial.mixin; + +import com.hrznstudio.spatial.api.ISpatialEntity; +import com.hrznstudio.spatial.api.ISpatialWorld; +import improbable.worker.EntityId; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Entity.class) +public abstract class MixinEntity implements ISpatialEntity { + @Shadow + public abstract World getEntityWorld(); + + private EntityId spatialId; + + @Override + public EntityId getSpatialId() { + return spatialId; + } + + @Override + public void setSpatialId(EntityId id) { + ISpatialWorld world = (ISpatialWorld) getEntityWorld(); + world.removeSpatial((Entity) (Object) this); + spatialId = id; + world.addSpatial((Entity) (Object) this); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntityPlayerSP.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntityPlayerSP.java index e241d03..090b6b5 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntityPlayerSP.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinEntityPlayerSP.java @@ -1,13 +1,11 @@ package com.hrznstudio.spatial.mixin; -import com.hrznstudio.spatial.SpatialMod; +import com.hrznstudio.spatial.api.ISpatialEntity; import com.hrznstudio.spatial.util.ConnectionManager; -import improbable.Coordinates; -import improbable.Position; +import improbable.Vector3f; import improbable.worker.EntityId; -import minecraft.entity.Motion; -import minecraft.entity.Player; import minecraft.entity.Rotation; +import minecraft.player.PlayerInput; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.util.math.AxisAlignedBB; import org.spongepowered.asm.mixin.Mixin; @@ -16,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(EntityPlayerSP.class) -public class MixinEntityPlayerSP { +public abstract class MixinEntityPlayerSP { @Shadow private int positionUpdateTicks; @@ -45,58 +43,50 @@ public class MixinEntityPlayerSP { @Redirect(method = "onUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;onUpdateWalkingPlayer()V")) public void onUpdateWalkingPlayer(EntityPlayerSP playerSP) { if (ConnectionManager.getConnectionStatus().isConnected()) { - boolean flag = playerSP.isSprinting(); - - EntityId id = SpatialMod.getClientWorker().getPlayerId(); + EntityId id = ((ISpatialEntity) playerSP).getSpatialId(); if (id == null) { return; } - boolean uSp = false, uSn = false; - - if (flag != serverSprintState) { - uSp = true; - serverSprintState = flag; - } + PlayerInput.Update update = new PlayerInput.Update(); - boolean flag2 = playerSP.isSneaking(); + boolean sprinting = playerSP.isSprinting(); + boolean sneaking = playerSP.isSneaking(); - if (flag2 != serverSneakState) { - uSn = true; - serverSneakState = flag2; + if (sprinting != serverSprintState) { + update.setSprinting(sprinting); + serverSprintState = sprinting; } - if (uSn || uSp) { - ConnectionManager.getConnection().sendComponentUpdate(Player.COMPONENT, id, new Player.Update().setSneaking(flag2).setSprinting(flag)); + + if (sneaking != serverSneakState) { + update.setSneaking(sneaking); + serverSneakState = sneaking; } ++this.positionUpdateTicks; AxisAlignedBB axisalignedbb = playerSP.getEntityBoundingBox(); - double d0 = playerSP.posX - this.lastReportedPosX; - double d1 = axisalignedbb.minY - this.lastReportedPosY; - double d2 = playerSP.posZ - this.lastReportedPosZ; - double d3 = (double) (playerSP.rotationYaw - this.lastReportedYaw); - double d4 = (double) (playerSP.rotationPitch - this.lastReportedPitch); - boolean pos = d0 * d0 + d1 * d1 + d2 * d2 > 9.0E-4D; - boolean rot = d3 != 0.0D || d4 != 0.0D; + double xChange = playerSP.posX - this.lastReportedPosX; + double yChange = axisalignedbb.minY - this.lastReportedPosY; + double zChange = playerSP.posZ - this.lastReportedPosZ; + boolean pos = xChange * xChange + yChange * yChange + zChange * zChange > 9.0E-4D; + boolean rot = (playerSP.rotationYaw - this.lastReportedYaw) != 0.0D || (playerSP.rotationPitch - this.lastReportedPitch) != 0.0D; if (pos) { - ConnectionManager.getConnection().sendComponentUpdate(Position.COMPONENT, id, new Position.Update().setCoords(new Coordinates(playerSP.posX, playerSP.posY, playerSP.posZ))); + update.setMovePosition(new Vector3f((float) playerSP.posX, (float) playerSP.posY, (float) playerSP.posZ)); this.lastReportedPosX = playerSP.posX; this.lastReportedPosY = axisalignedbb.minY; this.lastReportedPosZ = playerSP.posZ; this.positionUpdateTicks = 0; } + update.setDesiredMotion(new Vector3f((float) playerSP.motionX, (float) playerSP.motionY, (float) playerSP.motionZ)); if (rot) { ConnectionManager.getConnection().sendComponentUpdate(Rotation.COMPONENT, id, new Rotation.Update().setPitch(playerSP.rotationPitch).setYaw(playerSP.rotationYaw)); this.lastReportedYaw = playerSP.rotationYaw; this.lastReportedPitch = playerSP.rotationPitch; } - ConnectionManager.getConnection().sendComponentUpdate(Motion.COMPONENT, id, new Motion.Update().setCoords(new Coordinates( - playerSP.motionX, - playerSP.motionY, - playerSP.motionZ - ))); + + ConnectionManager.getConnection().sendComponentUpdate(PlayerInput.COMPONENT, id, update); this.positionUpdateTicks = 0; } diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinPlayerControllerMP.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinPlayerControllerMP.java new file mode 100644 index 0000000..ea73d1d --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinPlayerControllerMP.java @@ -0,0 +1,36 @@ +package com.hrznstudio.spatial.mixin; + +import com.hrznstudio.spatial.SpatialMod; +import com.hrznstudio.spatial.api.ISpatialEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.multiplayer.PlayerControllerMP; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.stats.RecipeBook; +import net.minecraft.stats.StatisticsManager; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(PlayerControllerMP.class) +public abstract class MixinPlayerControllerMP { + @Shadow + @Final + private NetHandlerPlayClient connection; + + @Shadow + @Final + private Minecraft mc; + + /** + * @author Coded + */ + @Overwrite + public EntityPlayerSP createPlayer(World p_192830_1_, StatisticsManager p_192830_2_, RecipeBook p_192830_3_) { + EntityPlayerSP sp = new EntityPlayerSP(this.mc, p_192830_1_, this.connection, p_192830_2_, p_192830_3_); + ((ISpatialEntity) sp).setSpatialId(SpatialMod.getClientWorker().getPlayerId()); + return sp; + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinWorld.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinWorld.java new file mode 100644 index 0000000..55db4de --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/mixin/MixinWorld.java @@ -0,0 +1,46 @@ +package com.hrznstudio.spatial.mixin; + +import com.hrznstudio.spatial.api.ISpatialEntity; +import com.hrznstudio.spatial.api.ISpatialWorld; +import improbable.worker.EntityId; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(World.class) +public abstract class MixinWorld implements ISpatialWorld { + private final Long2ObjectMap entitiesBySpatialId = new Long2ObjectOpenHashMap<>(); + + + @Inject(method = "onEntityAdded", at = @At("HEAD")) + public void onEntityAdded(Entity entity, CallbackInfo info) { + addSpatial(entity); + } + + @Inject(method = "onEntityRemoved", at = @At("HEAD")) + public void onEntityRemoved(Entity entity, CallbackInfo info) { + removeSpatial(entity); + } + + @Override + public Entity getEntityById(EntityId id) { + return entitiesBySpatialId.get(id.getInternalId()); + } + + @Override + public void addSpatial(Entity entity) { + if (entity instanceof ISpatialEntity && ((ISpatialEntity) entity).getSpatialId() != null) + entitiesBySpatialId.put(((ISpatialEntity) entity).getSpatialId().getInternalId(), entity); + } + + @Override + public void removeSpatial(Entity entity) { + if (entity instanceof ISpatialEntity && ((ISpatialEntity) entity).getSpatialId() != null) + entitiesBySpatialId.remove(((ISpatialEntity) entity).getSpatialId().getInternalId(), entity); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/snapshot/WorldConverter.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/snapshot/WorldConverter.java index 6032969..78d28a6 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/snapshot/WorldConverter.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/snapshot/WorldConverter.java @@ -17,7 +17,9 @@ import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.RegionFileCache; +import net.minecraftforge.common.util.Constants; import java.io.DataInputStream; import java.io.File; @@ -29,29 +31,29 @@ import java.util.stream.Stream; public class WorldConverter { - private static int worldSize = 64; + private static int worldSize = 128; private static final String CHUNK = "chunk"; private static final WorkerRequirementSet CHUNK_REQUIREMENT_SET = new WorkerRequirementSet(Collections.singletonList(new WorkerAttributeSet(Collections.singletonList("chunk_worker")))); public static void main(String[] args) throws Exception { SnapshotOutputStream outputStream = new SnapshotOutputStream("default.snapshot"); - final int chunks = (worldSize/2) >> 4; + final int chunks = (worldSize / 2) >> 4; final int negativeChunks = -chunks; long currentEntityId = 1; File world = new File("world"); NBTTagCompound leveldat = CompressedStreamTools.readCompressed(new FileInputStream(new File(world, "level.dat"))); - Map map = new HashMap<>(); - if(leveldat.hasKey("FML")) { + Map map = new HashMap<>(); + if (leveldat.hasKey("FML")) { leveldat .getCompoundTag("FML") .getCompoundTag("Registries") .getCompoundTag("minecraft:blocks") .getTagList("ids", 10) - .forEach(nbtBase -> map.put(((NBTTagCompound) nbtBase).getByte("V"), new Block(((NBTTagCompound) nbtBase).getString("K")))); + .forEach(nbtBase -> map.put((int) ((NBTTagCompound) nbtBase).getByte("V"), new Block(((NBTTagCompound) nbtBase).getString("K")))); } else { Gson gson = new Gson(); BlockData[] arr = gson.fromJson(new FileReader(new File("data.json")), BlockData[].class); - Stream.of(arr).forEach(blockData -> map.putIfAbsent((byte) blockData.type, new Block("minecraft:" + blockData.textType))); + Stream.of(arr).forEach(blockData -> map.putIfAbsent(blockData.type, new Block("minecraft:" + blockData.textType))); } for (int x = negativeChunks; x < chunks; x++) { for (int z = negativeChunks; z < chunks; z++) { @@ -66,19 +68,29 @@ public static void main(String[] args) throws Exception { Map> chunkData = new HashMap<>(); NBTTagCompound level = compound.getCompoundTag("Level"); NBTTagList sections = level.getTagList("Sections", 10); - for(int wah = 0; wah > 8) & 15; //y int l = i >> 4 & 15; //z + int extensionID = extensionNibble == null ? 0 : extensionNibble.get(j, k, l); + int blockID = extensionID << 8 | (b & 255); + int meta = metaNibble.get(j, k, l); + if (map.get(blockID).getId().equals("minecraft:air")) + continue; chunkData.putIfAbsent((int) section.getByte("Y"), new HashMap<>()); - chunkData.get((int) section.getByte("Y")).put(Converters.blockPosToChunkIndex(j, k, l), new State(map.get(b), metaArray[i % metaArray.length])); + chunkData.get((int) section.getByte("Y")).put(Converters.blockPosToChunkIndex(j, k, l), new State(map.get(blockID), meta)); } } diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/CommonWorkerRequirements.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/CommonWorkerRequirements.java index 8aeee62..20b8b11 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/CommonWorkerRequirements.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/CommonWorkerRequirements.java @@ -4,29 +4,30 @@ import improbable.WorkerAttributeSet; import improbable.WorkerRequirementSet; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class CommonWorkerRequirements { public static WorkerRequirementSet getAllCommonWorkers() { - return createWorkerRequirementSet("horizon_server", "horizon_client", "chunk_worker"); + return createWorkerRequirementSet("horizon_server", "horizon_client", "chunk_worker", "entity_worker"); } public static WorkerRequirementSet getEntityWorkers() { // return createWorkerAttributeSet("horizon_server", "horizon_client"); - return createWorkerRequirementSet("horizon_server", "horizon_client", "chunk_worker"); + return createWorkerRequirementSet("horizon_server", "horizon_client", "entity_worker"); } - private static WorkerAttributeSet createWorkerAttributeSet(String... attributes) { + public static WorkerAttributeSet createWorkerAttributeSet(String... attributes) { return new WorkerAttributeSet(Lists.newArrayList(attributes)); } - private static List createWorkerAttributeSets(String... attributes) { + public static List createWorkerAttributeSets(String... attributes) { return Stream.of(attributes).map(CommonWorkerRequirements::createWorkerAttributeSet).collect(Collectors.toList()); } - private static WorkerRequirementSet createWorkerRequirementSet(String... attributes) { + public static WorkerRequirementSet createWorkerRequirementSet(String... attributes) { return new WorkerRequirementSet(createWorkerAttributeSets(attributes)); } diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/ConnectionManager.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/ConnectionManager.java index 6bd30ad..035f06b 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/ConnectionManager.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/ConnectionManager.java @@ -1,5 +1,6 @@ package com.hrznstudio.spatial.util; +import com.hrznstudio.spatial.api.IDispatcherLoop; import improbable.worker.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -97,10 +98,11 @@ private static Connection getConnection(final String workerId, final String work private static void runEventLoop() { java.time.Duration maxWait = java.time.Duration.ofMillis(Math.round(1000.0 / UPDATES_PER_SECOND)); while (isConnected()) { + if(dispatcher instanceof IDispatcherLoop) + ((IDispatcherLoop) dispatcher).onLoop(); long startTime = System.nanoTime(); OpList opList = connection.getOpList(0); processingPool.submit(() -> dispatcher.process(opList)); - long stopTime = System.nanoTime(); java.time.Duration waitFor = maxWait.minusNanos(stopTime - startTime); try { diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/EntityRequirementCallback.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/EntityRequirementCallback.java new file mode 100644 index 0000000..9f2d126 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/EntityRequirementCallback.java @@ -0,0 +1,130 @@ +package com.hrznstudio.spatial.util; + +import improbable.Metadata; +import improbable.MetadataData; +import improbable.worker.ComponentMetaclass; +import improbable.worker.Dispatcher; +import improbable.worker.EntityId; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EntityRequirementCallback { + private final Map, Object>> map; + private final Callback callback; + private final List> requirements; + + private EntityRequirementCallback(Dispatcher dispatcher, Callback callback, List> requirements) { + this.callback = callback; + map = new HashMap<>(); + this.requirements = requirements; + for (Requirement requirement : requirements) { + dispatcher.onAddComponent(requirement.getMetaclass(), argument -> addEntityMetaclassToMap(argument.entityId, requirement.getMetaclass(), argument.data, requirement)); + } + + dispatcher.onRemoveEntity(argument -> map.remove(argument.entityId)); + } + + public static Builder builder(Callback callback) { + return new Builder(callback); + } + + private , DATA> void addEntityMetaclassToMap(EntityId id, META metaclass, DATA data, Requirement requirement) { + if (requirement.isValid(data)) { + map.computeIfAbsent(id, id1 -> { + Map, Object> map = new HashMap<>(); + for (Requirement requirement1 : requirements) { + map.put(requirement1.getMetaclass(), null); + } + return map; + }).put(metaclass, data); + update(id); + } + } + + private boolean allPresent(EntityId id) { + return this.map.get(id).entrySet().stream().noneMatch(entry -> entry.getValue() == null); + } + + private void update(EntityId id) { + if (allPresent(id)) { + callback.on(id); + map.remove(id); + } + } + + public interface Requirement, DATA> { + META getMetaclass(); + + boolean isValid(DATA data); + } + + @FunctionalInterface + public interface Callback { + void on(EntityId entityId); + } + + public static class GenericRequirement, DATA> implements Requirement { + private final META metaclass; + + public GenericRequirement(META metaclass) { + this.metaclass = metaclass; + } + + @Override + public META getMetaclass() { + return metaclass; + } + + @Override + public boolean isValid(DATA o) { + return true; + } + } + + public static class EntityTypeRequirement implements Requirement { + private final String type; + + public EntityTypeRequirement(String type) { + this.type = type; + } + + @Override + public Metadata getMetaclass() { + return Metadata.COMPONENT; + } + + @Override + public boolean isValid(MetadataData metadataData) { + return type.equals(metadataData.getEntityType()); + } + } + + public static class Builder { + private final Callback callback; + private final List> requirements = new ArrayList<>(); + + private Builder(Callback callback) { + this.callback = callback; + } + + public Builder requireType(String type) { + return addRequirement(new EntityTypeRequirement(type)); + } + + public Builder requireComponent(ComponentMetaclass componentMetaclass) { + return addRequirement(new GenericRequirement<>(componentMetaclass)); + } + + public Builder addRequirement(Requirement requirement) { + requirements.add(requirement); + return this; + } + + public void attach(Dispatcher dispatcher) { + new EntityRequirementCallback(dispatcher, callback, requirements); + } + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/Util.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/Util.java new file mode 100644 index 0000000..13dca06 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/util/Util.java @@ -0,0 +1,23 @@ +package com.hrznstudio.spatial.util; + +import improbable.Metadata; +import improbable.worker.ComponentMetaclass; +import improbable.worker.Entity; + +import javax.annotation.Nullable; + +public class Util { + public static , DATA> DATA getData(Entity entity, META meta) { + return entity.get(meta).orElseThrow(new NullPointerException()); + } + + public static String getType(@Nullable Entity entity) { + if (entity == null) + return "ERROR"; + return getData(entity, Metadata.COMPONENT).getEntityType(); + } + + public static boolean isWithin(double a, double b, double dist) { + return Math.max(a - dist, b) == Math.min(b, a + dist); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/BaseWorker.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/BaseWorker.java index 05b75b0..b783476 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/BaseWorker.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/BaseWorker.java @@ -1,6 +1,7 @@ package com.hrznstudio.spatial.worker; import com.hrznstudio.spatial.util.ConnectionManager; +import improbable.worker.Connection; import improbable.worker.Dispatcher; import improbable.worker.Ops; import improbable.worker.View; @@ -93,6 +94,9 @@ public Logger getLogger() { public D getDispatcher() { return dispatcher; } + public Connection getConnection() { + return ConnectionManager.getConnection(); + } /** * Base worker class providing login and {@link Dispatcher} support trough the default {@link Dispatcher} implementation diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/bootstrap/Bootstrapper.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/bootstrap/Bootstrapper.java new file mode 100644 index 0000000..8503ee5 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/bootstrap/Bootstrapper.java @@ -0,0 +1,29 @@ +package com.hrznstudio.spatial.worker.bootstrap; + +import com.hrznstudio.spatial.worker.BaseWorker; +import minecraft.boostrap.Bootstrap; +import minecraft.boostrap.Message; +import minecraft.general.Void; +import net.minecraft.util.text.TextComponentString; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.ServerChatEvent; + +public class Bootstrapper extends BaseWorker.BaseViewWorker { + public Bootstrapper() { + net.minecraft.init.Bootstrap.register(); + } + + @Override + protected void onConnected() { + getDispatcher().onCommandRequest(Bootstrap.Commands.ON_CHAT, argument -> { + String message = argument.request.getMessage(); + //TODO: need a player entity + ServerChatEvent event = new ServerChatEvent(null, message, new TextComponentString(message)); + if (!MinecraftForge.EVENT_BUS.post(event)) { + Message responseMessage = Message.create(); + responseMessage.setMessage(event.getComponent().getFormattedText()); + getConnection().sendCommandResponse(Bootstrap.Commands.ON_CHAT, argument.requestId, Void.create()); + } + }); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/chunk/ChunkWorker.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/chunk/ChunkWorker.java index fe3ced9..c7dda85 100644 --- a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/chunk/ChunkWorker.java +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/chunk/ChunkWorker.java @@ -13,6 +13,7 @@ import minecraft.world.ChunkStorage; import minecraft.world.ChunkStorageData; import minecraft.world.State; +import net.minecraft.init.Bootstrap; import java.util.Collections; import java.util.LinkedHashMap; @@ -24,6 +25,10 @@ public final class ChunkWorker extends BaseWorker.BaseViewWorker { private static final WorkerRequirementSet CHUNK_REQUIREMENT_SET = new WorkerRequirementSet(Collections.singletonList(new WorkerAttributeSet(Collections.singletonList("chunk_worker")))); private final Map tmpChunk; + public ChunkWorker() { + Bootstrap.register(); + } + { tmpChunk = new LinkedHashMap<>(); for (int i = 0; i < 16; i++) @@ -55,4 +60,4 @@ private int getIDForPos(int x, int y, int z) { protected void onConnected() { createChunk(ConnectionManager.getDispatcher(), ConnectionManager.getConnection(), new Coordinates(0, 0, 0)); } -} +} \ No newline at end of file diff --git a/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/entity/EntityWorker.java b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/entity/EntityWorker.java new file mode 100644 index 0000000..d1c6a09 --- /dev/null +++ b/workers/java/worker/src/main/java/com/hrznstudio/spatial/worker/entity/EntityWorker.java @@ -0,0 +1,102 @@ +package com.hrznstudio.spatial.worker.entity; + +import com.hrznstudio.spatial.util.ConnectionManager; +import com.hrznstudio.spatial.worker.BaseWorker; +import improbable.Coordinates; +import improbable.Position; +import improbable.Vector3f; +import improbable.collections.Option; +import improbable.worker.Authority; +import improbable.worker.EntityId; +import minecraft.entity.Motion; +import minecraft.entity.WorldEntity; +import minecraft.general.Void; +import minecraft.player.PlayerConnection; +import minecraft.player.PlayerInput; +import net.minecraft.init.Bootstrap; +import net.minecraft.util.EnumHand; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class EntityWorker extends BaseWorker.BaseViewWorker { + + public static Map playerTimeout = new HashMap<>(); + private final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1); + + public EntityWorker() { + Bootstrap.register(); + } + + @Override + protected void onConnected() { + getDispatcher().onAddComponent(PlayerConnection.COMPONENT, argument -> playerTimeout.put(argument.entityId, 5)); + getDispatcher().onComponentUpdate(PlayerConnection.COMPONENT, argument -> playerTimeout.put(argument.entityId, 5)); + getDispatcher().onAuthorityChange(WorldEntity.COMPONENT, argument -> { + if (argument.authority == Authority.AUTHORITATIVE) { + playerTimeout.put(argument.entityId, 5); + } else if (argument.authority == Authority.NOT_AUTHORITATIVE) { + playerTimeout.remove(argument.entityId); + } + }); + + getDispatcher().onCommandRequest(PlayerInput.Commands.ITEM_RIGHTCLICK, argument -> { + System.out.println("Received right click with hand " + (argument.request.getMain() ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND).name()); + getConnection().sendCommandResponse(PlayerInput.Commands.ITEM_RIGHTCLICK, argument.requestId, Void.create()); + }); + + getDispatcher().onComponentUpdate(PlayerInput.COMPONENT, argument -> { + if (getDispatcher().getAuthority(Position.COMPONENT, argument.entityId) != Authority.NOT_AUTHORITATIVE) { + Vector3f pos = argument.update.getMovePosition().orElse(null); + if (pos != null) { + ConnectionManager.getConnection().sendComponentUpdate( + Position.COMPONENT, + argument.entityId, + new Position.Update() + .setCoords( + new Coordinates( + pos.getX(), //TODO: Put some checks in here to make sure this position isn't speed hack + pos.getY(), + pos.getZ() + ) + ) + ); + } + Vector3f motion = argument.update.getDesiredMotion().orElse(null); + if (motion != null) { + ConnectionManager.getConnection().sendComponentUpdate( + Motion.COMPONENT, + argument.entityId, + new Motion.Update() + .setMotion( + new Vector3f( + motion.getX(), //TODO: Put some checks in here to make sure this motion isn't speed hack + motion.getY(), + motion.getZ() + ) + ) + ); + } + } + }); + + service.scheduleAtFixedRate(() -> { + if (!playerTimeout.isEmpty()) { + new HashSet<>(playerTimeout.keySet()).forEach(id -> { + int i = playerTimeout.get(id); + if (i == 0) { + ConnectionManager.getConnection().sendDeleteEntityRequest(id, Option.empty()); + System.out.println("Removing entity " + id.getInternalId()); + playerTimeout.remove(id); + } else { + playerTimeout.put(id, i - 1); + } + }); + } + }, 0, 1, TimeUnit.SECONDS); + } +} \ No newline at end of file diff --git a/workers/java/worker/src/main/resources/META-INF/services/com.hrznstudio.spatial.worker.WorkerService b/workers/java/worker/src/main/resources/META-INF/services/com.hrznstudio.spatial.worker.WorkerService index abb7174..e8c53d8 100644 --- a/workers/java/worker/src/main/resources/META-INF/services/com.hrznstudio.spatial.worker.WorkerService +++ b/workers/java/worker/src/main/resources/META-INF/services/com.hrznstudio.spatial.worker.WorkerService @@ -1 +1,3 @@ -com.hrznstudio.spatial.worker.chunk.ChunkWorker \ No newline at end of file +com.hrznstudio.spatial.worker.chunk.ChunkWorker +com.hrznstudio.spatial.worker.entity.EntityWorker +com.hrznstudio.spatial.worker.bootstrap.Bootstrapper \ No newline at end of file diff --git a/workers/java/worker/src/main/resources/META-INF/spatial_at.cfg b/workers/java/worker/src/main/resources/META-INF/spatial_at.cfg index 8c6c429..c5cedcd 100644 --- a/workers/java/worker/src/main/resources/META-INF/spatial_at.cfg +++ b/workers/java/worker/src/main/resources/META-INF/spatial_at.cfg @@ -1,6 +1,9 @@ protected net.minecraft.network.NetworkManager field_150746_k #channel public net.minecraft.client.multiplayer.WorldClient field_73033_b #clientChunkProvider +public net.minecraft.client.gui.GuiMainMenu * #lets just do fuckin everything public net.minecraft.client.multiplayer.ChunkProviderClient * #lets just do fuckin everything +public net.minecraft.client.network.NetHandlerPlayClient * #lets just do fuckin everything +public net.minecraft.client.gui.GuiMainMenu func_73971_c(IIF)V #renderSkybox public net.minecraft.world.chunk.Chunk func_76590_a()V #generateHeightMap \ No newline at end of file diff --git a/workers/java/worker/src/main/resources/assets/expanse/map.dat b/workers/java/worker/src/main/resources/assets/expanse/map.dat new file mode 100644 index 0000000..923af8a Binary files /dev/null and b/workers/java/worker/src/main/resources/assets/expanse/map.dat differ diff --git a/workers/java/worker/src/main/resources/assets/minecraft/textures/gui/title/edition.png b/workers/java/worker/src/main/resources/assets/minecraft/textures/gui/title/edition.png new file mode 100644 index 0000000..1dc87d9 Binary files /dev/null and b/workers/java/worker/src/main/resources/assets/minecraft/textures/gui/title/edition.png differ diff --git a/workers/java/worker/src/main/resources/mixins.spatial.json b/workers/java/worker/src/main/resources/mixins.spatial.json index f4d08a2..5f91c8e 100644 --- a/workers/java/worker/src/main/resources/mixins.spatial.json +++ b/workers/java/worker/src/main/resources/mixins.spatial.json @@ -6,10 +6,13 @@ "target": "@env(DEFAULT)", "compatibilityLevel": "JAVA_8", "mixins": [ - "MixinPackageScanner" + "MixinPackageScanner", + "MixinWorld", + "MixinEntity" ], "client": [ "MixinEntityPlayerSP", - "MixinNetHandlerPlayClient" + "MixinNetHandlerPlayClient", + "MixinPlayerControllerMP" ] } \ No newline at end of file diff --git a/workers/java/worker/src/main/resources/services/com.hrznstudio.spatial.WorkerService b/workers/java/worker/src/main/resources/services/com.hrznstudio.spatial.WorkerService deleted file mode 100644 index 6fcf288..0000000 --- a/workers/java/worker/src/main/resources/services/com.hrznstudio.spatial.WorkerService +++ /dev/null @@ -1 +0,0 @@ -com.hrznstudio.spatial.chunk.ChunkWorker \ No newline at end of file