mirror of
				https://github.com/genxium/DelayNoMore
				synced 2025-11-04 05:17:52 +00:00 
			
		
		
		
	Added necessary js type exposure to jsexport.
This commit is contained in:
		@@ -1401,8 +1401,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			offenderWx, offenderWy := VirtualGridToWorldPos(offender.VirtualGridX, offender.VirtualGridY, pR.VirtualGridToWorldRatio)
 | 
								offenderWx, offenderWy := VirtualGridToWorldPos(offender.VirtualGridX, offender.VirtualGridY, pR.VirtualGridToWorldRatio)
 | 
				
			||||||
			bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
								bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
				
			||||||
			newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "MeleeBullet")
 | 
								newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
 | 
				
			||||||
			newBulletCollider.Data = meleeBullet
 | 
					 | 
				
			||||||
			pR.Space.Add(newBulletCollider)
 | 
								pR.Space.Add(newBulletCollider)
 | 
				
			||||||
			collisionSysMap[collisionBulletIndex] = newBulletCollider
 | 
								collisionSysMap[collisionBulletIndex] = newBulletCollider
 | 
				
			||||||
			bulletColliders[collisionBulletIndex] = newBulletCollider
 | 
								bulletColliders[collisionBulletIndex] = newBulletCollider
 | 
				
			||||||
@@ -1625,8 +1624,7 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32) {
 | 
				
			|||||||
	for _, player := range pR.Players {
 | 
						for _, player := range pR.Players {
 | 
				
			||||||
		wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
 | 
							wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
 | 
				
			||||||
		colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
 | 
							colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
 | 
				
			||||||
		playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0
 | 
							playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, player, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0
 | 
				
			||||||
		playerCollider.Data = player
 | 
					 | 
				
			||||||
		pR.Space.Add(playerCollider)
 | 
							pR.Space.Add(playerCollider)
 | 
				
			||||||
		// Keep track of the collider in "pR.CollisionSysMap"
 | 
							// Keep track of the collider in "pR.CollisionSysMap"
 | 
				
			||||||
		joinIndex := player.JoinIndex
 | 
							joinIndex := player.JoinIndex
 | 
				
			||||||
@@ -1637,8 +1635,7 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, barrier := range pR.Barriers {
 | 
						for _, barrier := range pR.Barriers {
 | 
				
			||||||
		boundaryUnaligned := barrier.Boundary
 | 
							boundaryUnaligned := barrier.Boundary
 | 
				
			||||||
		barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Barrier")
 | 
							barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, barrier, "Barrier")
 | 
				
			||||||
		barrierCollider.Data = barrier
 | 
					 | 
				
			||||||
		pR.Space.Add(barrierCollider)
 | 
							pR.Space.Add(barrierCollider)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
 | 
				
			|||||||
	topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
 | 
						topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
 | 
				
			||||||
	for i, playerPos := range playerPosList.Eles {
 | 
						for i, playerPos := range playerPosList.Eles {
 | 
				
			||||||
		colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
 | 
							colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
 | 
				
			||||||
		playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
 | 
							playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
 | 
				
			||||||
		Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos=(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
 | 
							Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos=(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
 | 
				
			||||||
		playerColliders[i] = playerCollider
 | 
							playerColliders[i] = playerCollider
 | 
				
			||||||
		space.Add(playerCollider)
 | 
							space.Add(playerCollider)
 | 
				
			||||||
@@ -53,7 +53,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	barrierLocalId := 0
 | 
						barrierLocalId := 0
 | 
				
			||||||
	for _, barrierUnaligned := range barrierList.Eles {
 | 
						for _, barrierUnaligned := range barrierList.Eles {
 | 
				
			||||||
		barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
 | 
							barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, nil, "Barrier")
 | 
				
			||||||
		Logger.Debug(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
 | 
							Logger.Debug(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
 | 
				
			||||||
		space.Add(barrierCollider)
 | 
							space.Add(barrierCollider)
 | 
				
			||||||
		barrierLocalId++
 | 
							barrierLocalId++
 | 
				
			||||||
@@ -122,7 +122,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
 | 
				
			|||||||
		xfac := float64(1.0)
 | 
							xfac := float64(1.0)
 | 
				
			||||||
		offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
 | 
							offenderWx, offenderWy := playerPosList.Eles[0].X, playerPosList.Eles[0].Y
 | 
				
			||||||
		bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
							bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
				
			||||||
		newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
 | 
							newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, "MeleeBullet")
 | 
				
			||||||
		space.Add(newBulletCollider)
 | 
							space.Add(newBulletCollider)
 | 
				
			||||||
		bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
 | 
							bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
 | 
				
			||||||
		Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
 | 
							Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
 | 
				
			||||||
@@ -145,7 +145,7 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
 | 
				
			|||||||
		offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
 | 
							offenderWx, offenderWy := playerPosList.Eles[1].X, playerPosList.Eles[1].Y
 | 
				
			||||||
		bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
							bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, "MeleeBullet")
 | 
							newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, "MeleeBullet")
 | 
				
			||||||
		space.Add(newBulletCollider)
 | 
							space.Add(newBulletCollider)
 | 
				
			||||||
		bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
 | 
							bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
 | 
				
			||||||
		Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
 | 
							Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,19 +22,20 @@ func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding
 | 
				
			|||||||
	return fmt.Sprintf("{%.2f, %.2f}", body.X+leftPadding+halfBoundingW-spaceOffsetX, body.Y+bottomPadding+halfBoundingH-spaceOffsetY)
 | 
						return fmt.Sprintf("{%.2f, %.2f}", body.X+leftPadding+halfBoundingW-spaceOffsetX, body.Y+bottomPadding+halfBoundingH-spaceOffsetY)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
 | 
					func GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
 | 
				
			||||||
	blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
 | 
						blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
 | 
				
			||||||
	return generateRectColliderInCollisionSpace(blX, blY, leftPadding+w+rightPadding, bottomPadding+h+topPadding, tag)
 | 
						return generateRectColliderInCollisionSpace(blX, blY, leftPadding+w+rightPadding, bottomPadding+h+topPadding, data, tag)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func generateRectColliderInCollisionSpace(blX, blY, w, h float64, tag string) *resolv.Object {
 | 
					func generateRectColliderInCollisionSpace(blX, blY, w, h float64, data interface{}, tag string) *resolv.Object {
 | 
				
			||||||
	collider := resolv.NewObject(blX, blY, w, h, tag) // Unlike its frontend counter part, the position of a "resolv.Object" must be specified by "bottom-left point" because "w" and "h" must be positive, see "resolv.Object.BoundsToSpace" for details
 | 
						collider := resolv.NewObject(blX, blY, w, h, tag) // Unlike its frontend counter part, the position of a "resolv.Object" must be specified by "bottom-left point" because "w" and "h" must be positive, see "resolv.Object.BoundsToSpace" for details
 | 
				
			||||||
	shape := resolv.NewRectangle(0, 0, w, h)
 | 
						shape := resolv.NewRectangle(0, 0, w, h)
 | 
				
			||||||
	collider.SetShape(shape)
 | 
						collider.SetShape(shape)
 | 
				
			||||||
 | 
					    collider.Data = data 
 | 
				
			||||||
	return collider
 | 
						return collider
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
 | 
					func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
 | 
				
			||||||
	aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
 | 
						aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
 | 
				
			||||||
	var w, h float64 = 0, 0
 | 
						var w, h float64 = 0, 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,6 +61,7 @@ func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceO
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
 | 
						collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
 | 
				
			||||||
	collider.SetShape(shape)
 | 
						collider.SetShape(shape)
 | 
				
			||||||
 | 
					    collider.Data = data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return collider
 | 
						return collider
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,11 @@
 | 
				
			|||||||
package dnmshared
 | 
					package dnmshared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						RING_BUFF_CONSECUTIVE_SET     = int32(0)
 | 
				
			||||||
 | 
						RING_BUFF_NON_CONSECUTIVE_SET = int32(1)
 | 
				
			||||||
 | 
						RING_BUFF_FAILED_TO_SET       = int32(2)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RingBuffer struct {
 | 
					type RingBuffer struct {
 | 
				
			||||||
	Ed        int32 // write index, open index
 | 
						Ed        int32 // write index, open index
 | 
				
			||||||
	St        int32 // read index, closed index
 | 
						St        int32 // read index, closed index
 | 
				
			||||||
@@ -48,15 +54,15 @@ func (rb *RingBuffer) Pop() interface{} {
 | 
				
			|||||||
	return pItem
 | 
						return pItem
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rb *RingBuffer) GetByOffset(offsetFromSt int32) interface{} {
 | 
					func (rb *RingBuffer) GetArrIdxByOffset(offsetFromSt int32) int32 {
 | 
				
			||||||
	if 0 == rb.Cnt {
 | 
						if 0 == rb.Cnt || 0 > offsetFromSt {
 | 
				
			||||||
		return nil
 | 
							return -1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	arrIdx := rb.St + offsetFromSt
 | 
						arrIdx := rb.St + offsetFromSt
 | 
				
			||||||
	if rb.St < rb.Ed {
 | 
						if rb.St < rb.Ed {
 | 
				
			||||||
		// case#1: 0...st...ed...N-1
 | 
							// case#1: 0...st...ed...N-1
 | 
				
			||||||
		if rb.St <= arrIdx && arrIdx < rb.Ed {
 | 
							if rb.St <= arrIdx && arrIdx < rb.Ed {
 | 
				
			||||||
			return rb.Eles[arrIdx]
 | 
								return arrIdx
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// if rb.St >= rb.Ed
 | 
							// if rb.St >= rb.Ed
 | 
				
			||||||
@@ -65,11 +71,19 @@ func (rb *RingBuffer) GetByOffset(offsetFromSt int32) interface{} {
 | 
				
			|||||||
			arrIdx -= rb.N
 | 
								arrIdx -= rb.N
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if arrIdx >= rb.St || arrIdx < rb.Ed {
 | 
							if arrIdx >= rb.St || arrIdx < rb.Ed {
 | 
				
			||||||
			return rb.Eles[arrIdx]
 | 
								return arrIdx
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (rb *RingBuffer) GetByOffset(offsetFromSt int32) interface{} {
 | 
				
			||||||
 | 
						arrIdx := rb.GetArrIdxByOffset(offsetFromSt)
 | 
				
			||||||
 | 
						if -1 == arrIdx {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rb.Eles[arrIdx]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
 | 
					func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
 | 
				
			||||||
@@ -78,3 +92,33 @@ func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return rb.GetByOffset(frameId - rb.StFrameId)
 | 
						return rb.GetByOffset(frameId - rb.StFrameId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// [WARNING] During a battle, frontend could receive non-consecutive frames (either renderFrame or inputFrame) due to resync, the buffer should handle these frames properly.
 | 
				
			||||||
 | 
					func (rb *RingBuffer) SetByFrameId(pItem interface{}, frameId int32) (int32, int32, int32) {
 | 
				
			||||||
 | 
						oldStFrameId, oldEdFrameId := rb.StFrameId, rb.EdFrameId
 | 
				
			||||||
 | 
						if frameId < oldStFrameId {
 | 
				
			||||||
 | 
							return RING_BUFF_FAILED_TO_SET, oldStFrameId, oldEdFrameId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// By now "rb.StFrameId <= frameId"
 | 
				
			||||||
 | 
						if oldEdFrameId > frameId {
 | 
				
			||||||
 | 
							arrIdx := rb.GetArrIdxByOffset(frameId - rb.StFrameId)
 | 
				
			||||||
 | 
							if -1 != arrIdx {
 | 
				
			||||||
 | 
								rb.Eles[arrIdx] = pItem
 | 
				
			||||||
 | 
								return RING_BUFF_CONSECUTIVE_SET, oldStFrameId, oldEdFrameId
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// By now "rb.EdFrameId <= frameId"
 | 
				
			||||||
 | 
						ret := RING_BUFF_CONSECUTIVE_SET
 | 
				
			||||||
 | 
						if oldEdFrameId < frameId {
 | 
				
			||||||
 | 
							rb.St, rb.Ed = 0, 0
 | 
				
			||||||
 | 
							rb.StFrameId, rb.EdFrameId = frameId, frameId
 | 
				
			||||||
 | 
							rb.Cnt = 0
 | 
				
			||||||
 | 
							ret = RING_BUFF_NON_CONSECUTIVE_SET
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// By now "rb.EdFrameId == frameId"
 | 
				
			||||||
 | 
						rb.Put(pItem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret, oldStFrameId, oldEdFrameId
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -440,7 +440,7 @@
 | 
				
			|||||||
      "array": [
 | 
					      "array": [
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        209.73151519075364,
 | 
					        215.95961841836203,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1361
									
								
								frontend/assets/scenes/offline_map_2.fire
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1361
									
								
								frontend/assets/scenes/offline_map_2.fire
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										7
									
								
								frontend/assets/scenes/offline_map_2.fire.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								frontend/assets/scenes/offline_map_2.fire.meta
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "ver": "1.2.5",
 | 
				
			||||||
 | 
					  "uuid": "8491a86c-bec9-4813-968a-128ca01639e0",
 | 
				
			||||||
 | 
					  "asyncLoadAssets": false,
 | 
				
			||||||
 | 
					  "autoReleaseAssets": false,
 | 
				
			||||||
 | 
					  "subMetas": {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										238
									
								
								frontend/assets/scripts/OfflineMapBackend.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								frontend/assets/scripts/OfflineMapBackend.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,238 @@
 | 
				
			|||||||
 | 
					const i18n = require('LanguageData');
 | 
				
			||||||
 | 
					i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const OnlineMap = require('./Map');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cc.Class({
 | 
				
			||||||
 | 
					  extends: OnlineMap,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onDestroy() {
 | 
				
			||||||
 | 
					    console.warn("+++++++ Map onDestroy()");
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onLoad() {
 | 
				
			||||||
 | 
					    const self = this;
 | 
				
			||||||
 | 
					    window.mapIns = self;
 | 
				
			||||||
 | 
					    self.showCriticalCoordinateLabels = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mapNode = self.node;
 | 
				
			||||||
 | 
					    const canvasNode = mapNode.parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.mainCameraNode = self.canvasNode.getChildByName("Main Camera");
 | 
				
			||||||
 | 
					    self.mainCamera = self.mainCameraNode.getComponent(cc.Camera);
 | 
				
			||||||
 | 
					    for (let child of self.mainCameraNode.children) {
 | 
				
			||||||
 | 
					      child.setScale(1 / self.mainCamera.zoomRatio);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    self.widgetsAboveAllNode = self.mainCameraNode.getChildByName("WidgetsAboveAll");
 | 
				
			||||||
 | 
					    self.mainCameraNode.setPosition(cc.v2());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Init required prefab ended. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.inputDelayFrames = 8;
 | 
				
			||||||
 | 
					    self.inputScaleFrames = 2;
 | 
				
			||||||
 | 
					    self.inputFrameUpsyncDelayTolerance = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.renderCacheSize = 1024;
 | 
				
			||||||
 | 
					    self.serverFps = 60;
 | 
				
			||||||
 | 
					    self.rollbackEstimatedDt = 0.016667;
 | 
				
			||||||
 | 
					    self.rollbackEstimatedDtMillis = 16.667;
 | 
				
			||||||
 | 
					    self.rollbackEstimatedDtNanos = 16666666;
 | 
				
			||||||
 | 
					    self.tooFastDtIntervalMillis = 0.5 * self.rollbackEstimatedDtMillis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.worldToVirtualGridRatio = 1000;
 | 
				
			||||||
 | 
					    self.virtualGridToWorldRatio = 1.0 / self.worldToVirtualGridRatio;
 | 
				
			||||||
 | 
					    self.meleeSkillConfig = {
 | 
				
			||||||
 | 
					      1: {
 | 
				
			||||||
 | 
					        // for offender
 | 
				
			||||||
 | 
					        startupFrames: 10,
 | 
				
			||||||
 | 
					        activeFrames: 20,
 | 
				
			||||||
 | 
					        recoveryFrames: 34, // usually but not always "startupFrames+activeFrames", I hereby set it to be 1 frame more than the actual animation to avoid critical transition, i.e. when the animation is 1 frame from ending but "rdfPlayer.framesToRecover" is already counted 0 and the player triggers an other same attack, making an effective bullet trigger but no animation is played due to same animName is still playing
 | 
				
			||||||
 | 
					        recoveryFramesOnBlock: 34,
 | 
				
			||||||
 | 
					        recoveryFramesOnHit: 34,
 | 
				
			||||||
 | 
					        moveforward: {
 | 
				
			||||||
 | 
					          x: 0,
 | 
				
			||||||
 | 
					          y: 0,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        hitboxOffset: 12.0, // should be about the radius of the PlayerCollider 
 | 
				
			||||||
 | 
					        hitboxSize: {
 | 
				
			||||||
 | 
					          x: 23.0,
 | 
				
			||||||
 | 
					          y: 32.0,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // for defender
 | 
				
			||||||
 | 
					        hitStunFrames: 18,
 | 
				
			||||||
 | 
					        blockStunFrames: 9,
 | 
				
			||||||
 | 
					        pushback: 8.0,
 | 
				
			||||||
 | 
					        releaseTriggerType: 1, // 1: rising-edge, 2: falling-edge  
 | 
				
			||||||
 | 
					        damage: 5
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 
 | 
				
			||||||
 | 
					    [WARNING] As when a character is standing on a barrier, if not carefully curated there MIGHT BE a bouncing sequence of "[(inAir -> dropIntoBarrier ->), (notInAir -> pushedOutOfBarrier ->)], [(inAir -> ..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Moreover, "snapIntoPlatformOverlap" should be small enough such that the walking "velX" or jumping initial "velY" can escape from it by 1 renderFrame (when jumping is triggered, the character is waived from snappig for 1 renderFrame).
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    self.snapIntoPlatformOverlap = 0.1;
 | 
				
			||||||
 | 
					    self.snapIntoPlatformThreshold = 0.5; // a platform must be "horizontal enough" for a character to "stand on"
 | 
				
			||||||
 | 
					    self.jumpingInitVelY = 7 * self.worldToVirtualGridRatio; // unit: (virtual grid length/renderFrame)
 | 
				
			||||||
 | 
					    [self.gravityX, self.gravityY] = [0, -0.5*self.worldToVirtualGridRatio]; // unit: (virtual grid length/renderFrame^2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const tiledMapIns = self.node.getComponent(cc.TiledMap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const fullPathOfTmxFile = cc.js.formatStr("map/%s/map", "dungeon");
 | 
				
			||||||
 | 
					    cc.loader.loadRes(fullPathOfTmxFile, cc.TiledMapAsset, (err, tmxAsset) => {
 | 
				
			||||||
 | 
					      if (null != err) {
 | 
				
			||||||
 | 
					        console.error(err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tiledMapIns.tmxAsset = null;
 | 
				
			||||||
 | 
					      mapNode.removeAllChildren();
 | 
				
			||||||
 | 
					      self._resetCurrentMatch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (self.showCriticalCoordinateLabels) {
 | 
				
			||||||
 | 
					        const drawer = new cc.Node();
 | 
				
			||||||
 | 
					        drawer.setPosition(cc.v2(0, 0))
 | 
				
			||||||
 | 
					        safelyAddChild(self.node, drawer);
 | 
				
			||||||
 | 
					        setLocalZOrder(drawer, 999);
 | 
				
			||||||
 | 
					        const g = drawer.addComponent(cc.Graphics);
 | 
				
			||||||
 | 
					        g.lineWidth = 2;
 | 
				
			||||||
 | 
					        self.g = g;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tiledMapIns.tmxAsset = tmxAsset;
 | 
				
			||||||
 | 
					      const newMapSize = tiledMapIns.getMapSize();
 | 
				
			||||||
 | 
					      const newTileSize = tiledMapIns.getTileSize();
 | 
				
			||||||
 | 
					      self.node.setContentSize(newMapSize.width * newTileSize.width, newMapSize.height * newTileSize.height);
 | 
				
			||||||
 | 
					      self.node.setPosition(cc.v2(0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let barrierIdCounter = 0;
 | 
				
			||||||
 | 
					      const boundaryObjs = tileCollisionManager.extractBoundaryObjects(self.node);
 | 
				
			||||||
 | 
					      for (let boundaryObj of boundaryObjs.barriers) {
 | 
				
			||||||
 | 
					        const x0 = boundaryObj.anchor.x,
 | 
				
			||||||
 | 
					          y0 = boundaryObj.anchor.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const newBarrier = self.collisionSys.createPolygon(x0, y0, Array.from(boundaryObj, p => {
 | 
				
			||||||
 | 
					          return [p.x, p.y];
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        newBarrier.data = {
 | 
				
			||||||
 | 
					          hardPushback: true
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (false && self.showCriticalCoordinateLabels) {
 | 
				
			||||||
 | 
					          for (let i = 0; i < boundaryObj.length; ++i) {
 | 
				
			||||||
 | 
					            const barrierVertLabelNode = new cc.Node();
 | 
				
			||||||
 | 
					            switch (i % 4) {
 | 
				
			||||||
 | 
					              case 0:
 | 
				
			||||||
 | 
					                barrierVertLabelNode.color = cc.Color.RED;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 1:
 | 
				
			||||||
 | 
					                barrierVertLabelNode.color = cc.Color.GRAY;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              case 2:
 | 
				
			||||||
 | 
					                barrierVertLabelNode.color = cc.Color.BLACK;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              default:
 | 
				
			||||||
 | 
					                barrierVertLabelNode.color = cc.Color.MAGENTA;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const wx = boundaryObj.anchor.x + boundaryObj[i].x,
 | 
				
			||||||
 | 
					              wy = boundaryObj.anchor.y + boundaryObj[i].y;
 | 
				
			||||||
 | 
					            barrierVertLabelNode.setPosition(cc.v2(wx, wy));
 | 
				
			||||||
 | 
					            const barrierVertLabel = barrierVertLabelNode.addComponent(cc.Label);
 | 
				
			||||||
 | 
					            barrierVertLabel.fontSize = 12;
 | 
				
			||||||
 | 
					            barrierVertLabel.lineHeight = barrierVertLabel.fontSize + 1;
 | 
				
			||||||
 | 
					            barrierVertLabel.string = `(${wx.toFixed(1)}, ${wy.toFixed(1)})`;
 | 
				
			||||||
 | 
					            safelyAddChild(self.node, barrierVertLabelNode);
 | 
				
			||||||
 | 
					            setLocalZOrder(barrierVertLabelNode, 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            barrierVertLabelNode.active = true;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // console.log("Created barrier: ", newBarrier);
 | 
				
			||||||
 | 
					        ++barrierIdCounter;
 | 
				
			||||||
 | 
					        const collisionBarrierIndex = (self.collisionBarrierIndexPrefix + barrierIdCounter);
 | 
				
			||||||
 | 
					        self.collisionSysMap.set(collisionBarrierIndex, newBarrier);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const startRdf = window.pb.protos.RoomDownsyncFrame.create({
 | 
				
			||||||
 | 
					        id: window.MAGIC_ROOM_DOWNSYNC_FRAME_ID.BATTLE_START,
 | 
				
			||||||
 | 
					        players: {
 | 
				
			||||||
 | 
					          10: window.pb.protos.PlayerDownsync.create({
 | 
				
			||||||
 | 
					            id: 10,
 | 
				
			||||||
 | 
					            joinIndex: 1,
 | 
				
			||||||
 | 
					            virtualGridX: self.worldToVirtualGridPos(boundaryObjs.playerStartingPositions[0].x, boundaryObjs.playerStartingPositions[0].y)[0],
 | 
				
			||||||
 | 
					            virtualGridY: self.worldToVirtualGridPos(boundaryObjs.playerStartingPositions[0].x, boundaryObjs.playerStartingPositions[0].y)[1],
 | 
				
			||||||
 | 
					            speed: 1 * self.worldToVirtualGridRatio,
 | 
				
			||||||
 | 
					            colliderRadius: 12,
 | 
				
			||||||
 | 
					            characterState: window.ATK_CHARACTER_STATE.InAirIdle1[0],
 | 
				
			||||||
 | 
					            framesToRecover: 0,
 | 
				
			||||||
 | 
					            dirX: 0,
 | 
				
			||||||
 | 
					            dirY: 0,
 | 
				
			||||||
 | 
					            velX: 0,
 | 
				
			||||||
 | 
					            velY: 0,
 | 
				
			||||||
 | 
					            inAir: true,
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					          11: window.pb.protos.PlayerDownsync.create({
 | 
				
			||||||
 | 
					            id: 11,
 | 
				
			||||||
 | 
					            joinIndex: 2,
 | 
				
			||||||
 | 
					            virtualGridX: self.worldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y)[0],
 | 
				
			||||||
 | 
					            virtualGridY: self.worldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y)[1],
 | 
				
			||||||
 | 
					            speed: 1 * self.worldToVirtualGridRatio,
 | 
				
			||||||
 | 
					            colliderRadius: 12,
 | 
				
			||||||
 | 
					            characterState: window.ATK_CHARACTER_STATE.InAirIdle1[0],
 | 
				
			||||||
 | 
					            framesToRecover: 0,
 | 
				
			||||||
 | 
					            dirX: 0,
 | 
				
			||||||
 | 
					            dirY: 0,
 | 
				
			||||||
 | 
					            velX: 0,
 | 
				
			||||||
 | 
					            velY: 0,
 | 
				
			||||||
 | 
					            inAir: true,
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      self.selfPlayerInfo = {
 | 
				
			||||||
 | 
					        id: 11
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      self._initPlayerRichInfoDict(startRdf.players);
 | 
				
			||||||
 | 
					      self.onRoomDownsyncFrame(startRdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  update(dt) {
 | 
				
			||||||
 | 
					    const self = this;
 | 
				
			||||||
 | 
					    if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
 | 
				
			||||||
 | 
					      const elapsedMillisSinceLastFrameIdTriggered = performance.now() - self.lastRenderFrameIdTriggeredAt;
 | 
				
			||||||
 | 
					      if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) {
 | 
				
			||||||
 | 
					        // [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
 | 
				
			||||||
 | 
					        // console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        let st = performance.now();
 | 
				
			||||||
 | 
					        let prevSelfInput = null,
 | 
				
			||||||
 | 
					          currSelfInput = null;
 | 
				
			||||||
 | 
					        const noDelayInputFrameId = self._convertToInputFrameId(self.renderFrameId, 0); // It's important that "inputDelayFrames == 0" here 
 | 
				
			||||||
 | 
					        if (self.shouldGenerateInputFrameUpsync(self.renderFrameId)) {
 | 
				
			||||||
 | 
					          const prevAndCurrInputs = self._generateInputFrameUpsync(noDelayInputFrameId);
 | 
				
			||||||
 | 
					          prevSelfInput = prevAndCurrInputs[0];
 | 
				
			||||||
 | 
					          currSelfInput = prevAndCurrInputs[1];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const [prevRdf, rdf] = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.collisionSys, self.collisionSysMap, false);
 | 
				
			||||||
 | 
					        self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
 | 
				
			||||||
 | 
					        self.showDebugBoundaries(rdf);
 | 
				
			||||||
 | 
					        ++self.renderFrameId;
 | 
				
			||||||
 | 
					        self.lastRenderFrameIdTriggeredAt = performance.now();
 | 
				
			||||||
 | 
					        let t3 = performance.now();
 | 
				
			||||||
 | 
					      } catch (err) {
 | 
				
			||||||
 | 
					        console.error("Error during Map.update", err);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										9
									
								
								frontend/assets/scripts/OfflineMapBackend.js.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								frontend/assets/scripts/OfflineMapBackend.js.meta
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "ver": "1.0.5",
 | 
				
			||||||
 | 
					  "uuid": "b3810903-496b-43d7-8461-898cee958548",
 | 
				
			||||||
 | 
					  "isPlugin": false,
 | 
				
			||||||
 | 
					  "loadPluginInWeb": true,
 | 
				
			||||||
 | 
					  "loadPluginInNative": true,
 | 
				
			||||||
 | 
					  "loadPluginInEditor": false,
 | 
				
			||||||
 | 
					  "subMetas": {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,22 +1,67 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						. "dnmshared"
 | 
				
			||||||
 | 
						. "dnmshared/sharedprotos"
 | 
				
			||||||
	"github.com/gopherjs/gopherjs/js"
 | 
						"github.com/gopherjs/gopherjs/js"
 | 
				
			||||||
	"github.com/solarlune/resolv"
 | 
						"github.com/solarlune/resolv"
 | 
				
			||||||
    . "jsexport/protos"
 | 
					 | 
				
			||||||
	"jsexport/models"
 | 
						"jsexport/models"
 | 
				
			||||||
    . "dnmshared"
 | 
						. "jsexport/protos"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewRingBufferJs(n int32) *js.Object {
 | 
					 | 
				
			||||||
    return js.MakeWrapper(NewRingBuffer(n));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewCollisionSpaceJs(spaceW, spaceH, minStepW, minStepH int) *js.Object {
 | 
					func NewCollisionSpaceJs(spaceW, spaceH, minStepW, minStepH int) *js.Object {
 | 
				
			||||||
	return js.MakeWrapper(resolv.NewSpace(spaceW, spaceH, minStepW, minStepH))
 | 
						return js.MakeWrapper(resolv.NewSpace(spaceW, spaceH, minStepW, minStepH))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GenerateRectColliderJs(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, tag string) *js.Object {
 | 
					func NewVec2DJs(x, y float64) *js.Object {
 | 
				
			||||||
 | 
						return js.MakeFullWrapper(&Vec2D{
 | 
				
			||||||
 | 
							X: x,
 | 
				
			||||||
 | 
							Y: y,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewPolygon2DJs(anchor *Vec2D, points []*Vec2D) *js.Object {
 | 
				
			||||||
 | 
						return js.MakeFullWrapper(&Polygon2D{
 | 
				
			||||||
 | 
							Anchor: anchor,
 | 
				
			||||||
 | 
							Points: points,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewBarrierJs(boundary *Polygon2D) *js.Object {
 | 
				
			||||||
 | 
						return js.MakeWrapper(&Barrier{
 | 
				
			||||||
 | 
							Boundary: boundary,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, battleState, characterState, joinIndex, hp, maxHp int32, inAir bool, colliderRadius float64) *js.Object {
 | 
				
			||||||
 | 
						return js.MakeWrapper(&PlayerDownsync{
 | 
				
			||||||
 | 
							Id:             id,
 | 
				
			||||||
 | 
							VirtualGridX:   virtualGridX,
 | 
				
			||||||
 | 
							VirtualGridY:   virtualGridY,
 | 
				
			||||||
 | 
							DirX:           dirX,
 | 
				
			||||||
 | 
							DirY:           dirY,
 | 
				
			||||||
 | 
							VelX:           velX,
 | 
				
			||||||
 | 
							VelY:           velY,
 | 
				
			||||||
 | 
							Speed:          speed,
 | 
				
			||||||
 | 
							BattleState:    battleState,
 | 
				
			||||||
 | 
							JoinIndex:      joinIndex,
 | 
				
			||||||
 | 
							ColliderRadius: colliderRadius,
 | 
				
			||||||
 | 
							Hp:             hp,
 | 
				
			||||||
 | 
							MaxHp:          maxHp,
 | 
				
			||||||
 | 
							CharacterState: characterState,
 | 
				
			||||||
 | 
							InAir:          inAir,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewRoomDownsyncFrameJs(id int32, playersArr []*PlayerDownsync, meleeBullets []*MeleeBullet) *js.Object {
 | 
				
			||||||
 | 
						return js.MakeFullWrapper(&RoomDownsyncFrame{
 | 
				
			||||||
 | 
							Id:           id,
 | 
				
			||||||
 | 
							PlayersArr:   playersArr,
 | 
				
			||||||
 | 
							MeleeBullets: meleeBullets,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GenerateRectColliderJs(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *js.Object {
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	   [WARNING] It's important to note that we don't need "js.MakeFullWrapper" for a call sequence as follows.
 | 
						   [WARNING] It's important to note that we don't need "js.MakeFullWrapper" for a call sequence as follows.
 | 
				
			||||||
	   ```
 | 
						   ```
 | 
				
			||||||
@@ -26,24 +71,28 @@ func GenerateRectColliderJs(wx, wy, w, h, topPadding, bottomPadding, leftPadding
 | 
				
			|||||||
	   ```
 | 
						   ```
 | 
				
			||||||
	   The "space" variable doesn't need access to the field of "a" in JavaScript level to run "space.Add(...)" method, which is good.
 | 
						   The "space" variable doesn't need access to the field of "a" in JavaScript level to run "space.Add(...)" method, which is good.
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
    return js.MakeWrapper(GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, tag));
 | 
						return js.MakeWrapper(GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, data, tag))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CheckCollisionJs(obj *resolv.Object, dx, dy float64) *js.Object {
 | 
					func CheckCollisionJs(obj *resolv.Object, dx, dy float64) *js.Object {
 | 
				
			||||||
	// TODO: Support multiple tags in the future
 | 
						// TODO: Support multiple tags in the future
 | 
				
			||||||
	// Unfortunately I couldn't find a way to just call "var a = GenerateRectColliderJs(...); space.Add(a); a.Check(...)" to get the collision result, the unwrapped method will result in stack overflow. Need a better solution later.
 | 
						// Unfortunately I couldn't find a way to just call "var a = GenerateRectColliderJs(...); space.Add(a); a.Check(...)" to get the collision result, the unwrapped method will result in stack overflow. Need a better solution later.
 | 
				
			||||||
    return js.MakeFullWrapper(obj.Check(dx, dy));
 | 
						return js.MakeFullWrapper(obj.Check(dx, dy))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *js.Object {
 | 
					func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrame, delayedInputFrameForPrevRenderFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *js.Object {
 | 
				
			||||||
	// We need access to all fields of RoomDownsyncFrame for displaying in frontend
 | 
						// We need access to all fields of RoomDownsyncFrame for displaying in frontend
 | 
				
			||||||
    return js.MakeFullWrapper(models.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames, inputsBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio))
 | 
						return js.MakeFullWrapper(models.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delayedInputFrameForPrevRenderFrame, currRenderFrame, collisionSys, collisionSysMap, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	js.Global.Set("gopkgs", map[string]interface{}{
 | 
						js.Global.Set("gopkgs", map[string]interface{}{
 | 
				
			||||||
        "NewRingBufferJs": NewRingBufferJs,
 | 
							"NewVec2DJs":             NewVec2DJs,
 | 
				
			||||||
 | 
							"NewPolygon2DJs":         NewPolygon2DJs,
 | 
				
			||||||
 | 
							"NewBarrierJs":           NewBarrierJs,
 | 
				
			||||||
 | 
							"NewPlayerDownsyncJs":    NewPlayerDownsyncJs,
 | 
				
			||||||
 | 
							"NewRoomDownsyncFrameJs": NewRoomDownsyncFrameJs,
 | 
				
			||||||
		"NewCollisionSpaceJs":    NewCollisionSpaceJs,
 | 
							"NewCollisionSpaceJs":    NewCollisionSpaceJs,
 | 
				
			||||||
		"GenerateRectColliderJs": GenerateRectColliderJs,
 | 
							"GenerateRectColliderJs": GenerateRectColliderJs,
 | 
				
			||||||
		"CheckCollisionJs":       CheckCollisionJs,
 | 
							"CheckCollisionJs":       CheckCollisionJs,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/solarlune/resolv"
 | 
					 | 
				
			||||||
    . "dnmshared/sharedprotos"
 | 
					 | 
				
			||||||
    . "jsexport/protos"
 | 
					 | 
				
			||||||
	. "dnmshared"
 | 
						. "dnmshared"
 | 
				
			||||||
 | 
						. "dnmshared/sharedprotos"
 | 
				
			||||||
 | 
						"github.com/solarlune/resolv"
 | 
				
			||||||
 | 
						. "jsexport/protos"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -81,7 +81,7 @@ func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.C
 | 
				
			|||||||
	return ret
 | 
						return ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame {
 | 
					func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delayedInputFrameForPrevRenderFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame {
 | 
				
			||||||
	topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
 | 
						topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
 | 
				
			||||||
	// [WARNING] This function MUST BE called while "InputsBufferLock" is locked!
 | 
						// [WARNING] This function MUST BE called while "InputsBufferLock" is locked!
 | 
				
			||||||
	roomCapacity := len(currRenderFrame.PlayersArr)
 | 
						roomCapacity := len(currRenderFrame.PlayersArr)
 | 
				
			||||||
@@ -117,11 +117,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *Input
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 1. Process player inputs
 | 
						// 1. Process player inputs
 | 
				
			||||||
	if nil != delayedInputFrame {
 | 
						if nil != delayedInputFrame {
 | 
				
			||||||
		var delayedInputFrameForPrevRenderFrame *InputFrameDownsync = nil
 | 
					 | 
				
			||||||
		tmp := inputsBuffer.GetByFrameId(ConvertToInputFrameId(currRenderFrame.Id-1, inputDelayFrames, inputScaleFrames))
 | 
					 | 
				
			||||||
		if nil != tmp {
 | 
					 | 
				
			||||||
			delayedInputFrameForPrevRenderFrame = tmp.(*InputFrameDownsync)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		inputList := delayedInputFrame.InputList
 | 
							inputList := delayedInputFrame.InputList
 | 
				
			||||||
		for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
							for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
				
			||||||
			joinIndex := currPlayerDownsync.JoinIndex
 | 
								joinIndex := currPlayerDownsync.JoinIndex
 | 
				
			||||||
@@ -187,9 +182,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *Input
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 3. Invoke collision system stepping (no-op for backend collision lib)
 | 
						// 3. Calc pushbacks for each player (after its movement) w/o bullets
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 4. Calc pushbacks for each player (after its movement) w/o bullets
 | 
					 | 
				
			||||||
	for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
						for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
				
			||||||
		joinIndex := currPlayerDownsync.JoinIndex
 | 
							joinIndex := currPlayerDownsync.JoinIndex
 | 
				
			||||||
		collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
							collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
				
			||||||
@@ -201,6 +194,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *Input
 | 
				
			|||||||
		if collision := playerCollider.Check(0, 0); nil != collision {
 | 
							if collision := playerCollider.Check(0, 0); nil != collision {
 | 
				
			||||||
			for _, obj := range collision.Objects {
 | 
								for _, obj := range collision.Objects {
 | 
				
			||||||
				isBarrier, isAnotherPlayer, isBullet := false, false, false
 | 
									isBarrier, isAnotherPlayer, isBullet := false, false, false
 | 
				
			||||||
 | 
									// TODO: Make this part work in JavaScript without having to expose all types Barrier/PlayerDownsync/MeleeBullet by js.MakeWrapper.
 | 
				
			||||||
				switch obj.Data.(type) {
 | 
									switch obj.Data.(type) {
 | 
				
			||||||
				case *Barrier:
 | 
									case *Barrier:
 | 
				
			||||||
					isBarrier = true
 | 
										isBarrier = true
 | 
				
			||||||
@@ -262,7 +256,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *Input
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 7. Get players out of stuck barriers if there's any
 | 
						// 4. Get players out of stuck barriers if there's any
 | 
				
			||||||
	for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
						for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
 | 
				
			||||||
		joinIndex := currPlayerDownsync.JoinIndex
 | 
							joinIndex := currPlayerDownsync.JoinIndex
 | 
				
			||||||
		collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
							collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user