Fixed movement desc packets being discarded

- Added callback hook for movement events
This commit is contained in:
MrTJP committed 2015-06-28 17:40:45 -04:00
1 parent d6731ef60b
commit e5d3aa0561
11 files changed
+334 -108

No files matched your search

+5 -5
View File
@@ -27,14 +27,14 @@ public interface IFrame
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param side The side of the block, as a ForgeDirection
* @return True if the side can stick on to another block.
* @param side The side of this block, as a ForgeDirection
* @return True if the side can grab another block.
*/
boolean stickOut(World w, int x, int y, int z, int side);
/**
* Used to check if this frame block can be grabbed on the
* given side from another frame.
* given side by another frame.
*
* Convention requires that this method yields the same result
* on both client and server.
@@ -43,8 +43,8 @@ public interface IFrame
* @param x The x coordinate.
* @param y The y coordinate.
* @param z The z coordinate.
* @param side The side of the block, as a ForgeDirection
* @return True if the side can be stuck onto by a frame block.
* @param side The side of this block, as a ForgeDirection
* @return True if the side can be grabbed by a frame block.
*/
boolean stickIn(World w, int x, int y, int z, int side);
}
+1
View File
@@ -125,6 +125,7 @@ class TileMotor extends InstancedBlockTile with TTileOrient with IFrame
r.push()
r.setWorld(world)
r.setDirection(getMoveDir)
r.setSpeed(1/16D)
r.addBlocks(blocks)
r.execute()
r.pop()
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
*/
package mrtjp.relocation.api;
/**
* Interface that can be used by things that wish to receive events for
* a move that they executed. This interface is passed into the {@link Relocator}
* during movement construction.
*
* For example, a motor may wish to know when the movement completes. In which case,
* the motor tile itself would implement this interface and pass itself into the
* Relocator.
*
* These methods are only called server-side. Clients will not receive any of
* these events, as this class is registered during the execution of a move, which
* can only happen server-side.
*
*/
public interface IMovementCallback
{
/**
* Called once move starts. The descriptor contains methods that
* describe the state of the current movement that this callback
* was registered to.
*
* This descriptor is properly weak-referenced, keep or discard it
* at your own leasure.
*
* @param desc The movement descriptor for the current move.
*/
void setDescriptor(IMovementDescriptor desc);
/**
* Called when the movement starts, when the animation starts playing.
*/
void onMovementStarted();
/**
* Called when the movement completes, and all blocks have moved over.
*/
void onMovementFinished();
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
*/
package mrtjp.relocation.api;
/**
* This is the interface of the object that is given to an {@link IMovementCallback} so
* it may access movement information whenever it needs to during the movement.
*
* Results of all methods is only valid during movement, undefined otherwise. Use
* isMoving() to check before using any values from this.
*/
public interface IMovementDescriptor
{
/**
* @return True if the structure is moving.
*/
boolean isMoving();
/**
* @return The progress of the movement scaled between 0 and 1.
*/
double getProgress();
/**
* @return The size of the moving structure, zero if it is no longer moving.
*/
int getSize();
}
+28 -4
View File
@@ -16,10 +16,8 @@ import java.util.Set;
public abstract class Relocator
{
/**
* Pushes the instance of the Relocator onto the stack.
* Pushes an instance of the Relocator onto the stack.
* Must be called before using any methods.
*
* @throws IllegalStateException If the Relocator is already on the stack.
*/
public abstract void push();
@@ -27,7 +25,7 @@ public abstract class Relocator
* Pops the instance of the Relocator off the stack.
* Must be called after you are done using this.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If there is no Relocator on the stack.
*/
public abstract void pop();
@@ -35,6 +33,7 @@ public abstract class Relocator
* Sets the world for the movement.
*
* @param world The world in which the movement will occure.
* @throws IllegalStateException If the world was already set.
*/
public abstract void setWorld(World world);
@@ -45,9 +44,32 @@ public abstract class Relocator
* @param dir The direction to move the blocks.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If the direction was already set.
*/
public abstract void setDirection(int dir);
/**
* Sets the speed of the movement. Must be greater than 0 and
* less than 1.
*
* @param speed The speed of the movement, in meters/tick.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If the speed was already set.
*/
public abstract void setSpeed(double speed);
/**
* Sets a callback object that receives events during the actual move.
* This is optional and is not required to be set.
*
* @param callback The callback to register for this move.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If a callback was already set.
*/
public abstract void setCallback(IMovementCallback callback);
/**
* Following methods are used to add blocks to the queue.
*
@@ -64,6 +86,8 @@ public abstract class Relocator
* @return True if the movement was successfully started.
*
* @throws IllegalStateException If the Relocator is not on the stack.
* @throws IllegalStateException If any of the required parameters are not set
* or are invalid.
*/
public abstract boolean execute();
}
+7 -3
View File
@@ -18,7 +18,7 @@ import net.minecraft.world.World
import scala.collection.JavaConversions._
class BlockMovingRow extends InstancedBlock("relocation.BlockMovingRow", Material.iron)
class BlockMovingRow extends InstancedBlock("relocation.blockmovingrow", Material.iron)
{
setHardness(-1F)
setStepSound(Block.soundTypeGravel)
@@ -33,10 +33,14 @@ object TileMovingRow
w.setBlock(r.pos.x, r.pos.y, r.pos.z, RelocationMod.blockMovingRow, 0, 3)
}
def getBoxFor(w:World, r:BlockRow, progress:Double) =
def getBoxFor(w:World, r:BlockRow, progress:Double):Cuboid6 =
{
val p = r.pos.copy.offset(r.moveDir^1)
w.getBlock(p.x, p.y, p.z).getCollisionBoundingBoxFromPool(w, p.x, p.y, p.z) match
val bl = w.getBlock(p.x, p.y, p.z)
if (bl == RelocationMod.blockMovingRow) return Cuboid6.full.copy()
bl.getCollisionBoundingBoxFromPool(w, p.x, p.y, p.z) match
{
case aabb:AxisAlignedBB => new Cuboid6(aabb).sub(new Vector3(r.pos))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir))*progress)
+8 -7
View File
@@ -17,6 +17,7 @@ object RelocationEventHandler
def worldUnload(event:WorldEvent.Unload)
{
RelocationSPH.onWorldUnload(event.world)
MovementManager2.onWorldUnload(event.world)
}
@SubscribeEvent
@@ -40,13 +41,6 @@ object RelocationEventHandler
MovementManager2.onTick(false)
}
}
@SubscribeEvent
def clientTick(event:TickEvent.ClientTickEvent)
{
if (event.phase == TickEvent.Phase.END)
MovementManager2.onTick(true)
}
}
object RelocationClientEventHandler
@@ -64,4 +58,11 @@ object RelocationClientEventHandler
{
MovingRenderer.onRenderWorldEvent()
}
@SubscribeEvent
def clientTick(event:TickEvent.ClientTickEvent)
{
if (event.phase == TickEvent.Phase.END)
MovementManager2.onTick(true)
}
}
@@ -5,16 +5,10 @@
*/
package mrtjp.relocation.handler
import java.util.{Set => JSet}
import codechicken.lib.vec.BlockCoord
import mrtjp.relocation.api.{BlockPos, ITileMover, RelocationAPI, Relocator}
import mrtjp.relocation.api.{ITileMover, RelocationAPI}
import mrtjp.relocation.{MovementManager2, MovingTileRegistry}
import net.minecraft.world.World
import scala.collection.JavaConversions._
import scala.collection.mutable.{Set => MSet}
object RelocationAPI_Impl extends RelocationAPI
{
var isPreInit = true
@@ -41,73 +35,4 @@ object RelocationAPI_Impl extends RelocationAPI
override def isMoving(world:World, x:Int, y:Int, z:Int) =
MovementManager2.isMoving(world, x, y, z)
}
object Relocator_Impl extends Relocator
{
private var enabled = false
private var world:World = null
private var dir = -1
private val blocks = MSet[BlockCoord]()
private def assertState()
{
if (!enabled) throw new IllegalStateException("Relocator must be on the stack before use.")
}
override def push()
{
if (enabled) throw new IllegalStateException("Relocator is already on the stack.")
enabled = true
}
override def pop()
{
if (!enabled) throw new IllegalStateException("Relocator is not on the stack.")
enabled = false
world = null
dir = -1
blocks.clear()
}
override def setWorld(w:World)
{
assertState()
if (world != null) throw new IllegalStateException("World already set.")
world = w
}
override def setDirection(d:Int)
{
assertState()
if (dir != -1) throw new IllegalStateException("Direction already set.")
dir = d
}
override def addBlock(x:Int, y:Int, z:Int)
{
assertState()
blocks += new BlockCoord(x, y, z)
}
override def addBlock(bc:BlockPos)
{
addBlock(bc.x, bc.y, bc.z)
}
override def addBlocks(blocks:JSet[BlockPos])
{
for (b <- blocks) addBlock(b)
}
override def execute() =
{
assertState()
if (world == null) throw new IllegalStateException("World must be set before move.")
if (world.isRemote) throw new IllegalStateException("Movements cannot be executed client-side.")
if (dir == -1) throw new IllegalStateException("Direction must be set before move.")
if (blocks.isEmpty) throw new IllegalStateException("At least 1 block is required for move.")
MovementManager2.tryStartMove(world, blocks.toSet, dir)
}
}
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2015.
* Created by MrTJP.
* All rights reserved.
*/
package mrtjp.relocation.handler
import java.util.{Set => JSet}
import codechicken.lib.vec.BlockCoord
import mrtjp.relocation.MovementManager2
import mrtjp.relocation.api.{IMovementCallback, BlockPos, Relocator}
import net.minecraft.world.World
import scala.collection.JavaConversions._
import scala.collection.mutable.{Set => MSet, Stack => MStack}
class RelocationRun
{
var world:World = null
var dir = -1
var speed = 0.0
var callback:IMovementCallback = null
val blocks = MSet[BlockCoord]()
def clear()
{
world = null
dir = -1
speed = 0
callback = null
blocks.clear()
}
}
object Relocator_Impl extends Relocator
{
var mainStack = new MStack[RelocationRun]()
var tempStack = new MStack[RelocationRun]()
private def assertState()
{
if (mainStack.isEmpty) throw new IllegalStateException("Relocator stack is empty.")
}
override def push()
{
val r = if (tempStack.isEmpty) new RelocationRun else tempStack.pop()
mainStack.push(r)
}
override def pop()
{
assertState()
val r = mainStack.pop()
r.clear()
tempStack.push(r)
}
override def setWorld(world:World)
{
assertState()
val top = mainStack.top
if (top.world != null) throw new IllegalStateException("World already set.")
top.world = world
}
override def setDirection(dir:Int)
{
assertState()
val top = mainStack.top
if (top.dir != -1) throw new IllegalStateException("Direction already set.")
top.dir = dir
}
override def setSpeed(speed:Double)
{
assertState()
val top = mainStack.top
if (top.speed > 0) throw new IllegalStateException("Speed already set.")
top.speed = speed
}
override def setCallback(callback:IMovementCallback)
{
assertState()
val top = mainStack.top
if (top.callback != null) throw new IllegalStateException("Callback already set.")
top.callback = callback
}
override def addBlock(x:Int, y:Int, z:Int)
{
assertState()
mainStack.top.blocks += new BlockCoord(x, y, z)
}
override def addBlock(bc:BlockPos)
{
addBlock(bc.x, bc.y, bc.z)
}
override def addBlocks(blocks:JSet[BlockPos])
{
for (b <- blocks) addBlock(b)
}
override def execute() =
{
assertState()
val top = mainStack.top
if (top.world == null) throw new IllegalStateException("World must be set before move.")
if (top.world.isRemote) throw new IllegalStateException("Movements cannot be executed client-side.")
if (top.dir == -1) throw new IllegalStateException("Direction must be set before move.")
if (top.speed <= 0) throw new IllegalStateException("Speed must be greater than 0.")
if (top.speed >= 1) throw new IllegalStateException("Speed must be less than 1.")
if (top.blocks.isEmpty) throw new IllegalStateException("No blocks queued for move.")
MovementManager2.tryStartMove(top.world, top.blocks.toSet, top.dir, top.speed, top.callback)
}
}
@@ -84,7 +84,15 @@ object RelocationSPH extends RelocationPH with IServerPacketHandler
def onWorldUnload(world:World)
{
if(!world.isRemote)
{
updateMap.remove(world)
if (chunkWatchers.nonEmpty)
{
val players = getServerPlayers
for (p <- players) if (p.worldObj.provider.dimensionId == world.provider.dimensionId)
chunkWatchers.remove(p.getEntityId)
}
}
}
def onChunkWatch(p:EntityPlayer, c:ChunkCoordIntPair)
+79 -13
View File
@@ -10,12 +10,14 @@ import codechicken.lib.packet.PacketCustom
import codechicken.lib.vec.BlockCoord
import mrtjp.core.math.MathLib
import mrtjp.core.world.WorldLib
import mrtjp.relocation.handler.{RelocationSPH, RelocationConfig}
import mrtjp.relocation.api.{IMovementCallback, IMovementDescriptor}
import mrtjp.relocation.handler.{RelocationConfig, RelocationSPH}
import net.minecraft.init.Blocks
import net.minecraft.world.{ChunkCoordIntPair, World}
import net.minecraftforge.common.DimensionManager
import scala.collection.mutable.{HashMap => MHashMap, MultiMap => MMultiMap, Set => MSet}
import scala.ref.WeakReference
object MovementManager2
{
@@ -48,6 +50,7 @@ object MovementManager2
val struct = new BlockStruct
struct.id = id
struct.readDesc(in)
addStructToWorld(w, struct)
id = in.readUShort()
}
}
@@ -58,8 +61,8 @@ object MovementManager2
val struct = new BlockStruct
struct.id = in.readUShort()
struct.readDesc(in)
getWorldStructs(w).addStruct(struct)
for (b <- struct.allBlocks)
addStructToWorld(w, struct)
for (b <- struct.allBlocks) //rerender all moving blocks
w.func_147479_m(b.x, b.y, b.z)
case 2 =>
val id = in.readUShort()
@@ -88,10 +91,16 @@ object MovementManager2
def isMoving(w:World, x:Int, y:Int, z:Int) = getWorldStructs(w).contains(x, y, z)
def addStructToWorld(w:World, b:BlockStruct)
{
getWorldStructs(w).addStruct(b)
b.onAdded(w)
}
def getEnclosedStructure(w:World, x:Int, y:Int, z:Int) =
getWorldStructs(w).structs.find(_.contains(x, y, z)).orNull
def tryStartMove(w:World, blocks:Set[BlockCoord], moveDir:Int):Boolean =
def tryStartMove(w:World, blocks:Set[BlockCoord], moveDir:Int, speed:Double, c:IMovementCallback):Boolean =
{
if (blocks.size > RelocationConfig.moveLimit) return false
@@ -117,8 +126,10 @@ object MovementManager2
val struct = new BlockStruct
struct.id = BlockStruct.claimID()
struct.speed = speed
struct.rows = rows
getWorldStructs(w).addStruct(struct)
struct.callback = WeakReference(c)
addStructToWorld(w, struct)
sendStruct(w, struct)
true
@@ -156,9 +167,9 @@ object MovementManager2
def cycleMove(w:World, struct:BlockStruct)
{
for (r <- struct.rows) r.doMove(w)
for (r <- struct.rows) r.postMove(w)
for (r <- struct.rows) r.endMove(w)
struct.doMove(w)
struct.postMove(w)
struct.endMove(w)
Utils.rescheduleTicks(w, struct.preMoveBlocks, struct.allBlocks, struct.moveDir)
@@ -184,8 +195,8 @@ class WorldStructs
def removeFinished() =
{
val finished = structs.filter(_.finished)
structs = structs.filterNot(_.finished)
val finished = structs.filter(_.isFinished)
structs = structs.filterNot(_.isFinished)
finished
}
@@ -213,12 +224,34 @@ object BlockStruct
}
}
class MoveDesc(b:WeakReference[BlockStruct]) extends IMovementDescriptor
{
def this(b:BlockStruct) = this(new WeakReference(b))
override def isMoving = b match {
case WeakReference(b:BlockStruct) => !b.isFinished
case _ => false
}
override def getProgress = b match {
case WeakReference(b:BlockStruct) => b.progress
case _ => -1
}
override def getSize = b match {
case WeakReference(b:BlockStruct) => b.allBlocks.size
case _ => 0
}
}
class BlockStruct
{
var id = -1
var progress = 0.0D
var speed = 1/16D
var rows:Set[BlockRow] = Set.empty
var callback = WeakReference[IMovementCallback](null)
var progress = 0.0D
lazy val allBlocks = rows.flatMap(_.allBlocks)
lazy val preMoveBlocks = rows.flatMap(_.preMoveBlocks)
@@ -228,8 +261,9 @@ class BlockStruct
def contains(x:Int, y:Int, z:Int) = rows.exists(_.contains(x, y, z))
def push(){ progress = (progress+speed) min 1.0D }
def finished = progress >= 1.0D
def push(){ progress = math.min(1.0, progress+speed) }
def isFinished = progress >= 1.0D
def getChunks:Set[ChunkCoordIntPair] =
{
@@ -239,6 +273,37 @@ class BlockStruct
c.result()
}
def onAdded(w:World)
{
if (!w.isRemote) callback match
{
case WeakReference(c) =>
c.setDescriptor(new MoveDesc(this))
c.onMovementStarted()
case _ =>
}
}
def doMove(w:World)
{
for (r <- rows) r.doMove(w)
}
def postMove(w:World)
{
for (r <- rows) r.postMove(w)
}
def endMove(w:World)
{
for (r <- rows) r.endMove(w)
if (!w.isRemote) callback match
{
case WeakReference(c) => c.onMovementFinished()
case _ =>
}
}
override def equals(obj:scala.Any) = obj match
{
case that:BlockStruct => id == that.id
@@ -280,6 +345,7 @@ class BlockRow(val pos:BlockCoord, val moveDir:Int, val size:Int)
import MathLib.{basis, normal, shift}
import math.{max, min}
if (normal(x, y, z, moveDir) == normal(pos, moveDir))
{
val b1 = basis(pos, moveDir)