hud: wip scoreboard, fixes

This commit is contained in:
Bixilon 2021-11-02 15:44:27 +01:00
parent 489cbfc412
commit 5f28cceb49
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
27 changed files with 370 additions and 45 deletions

View File

@ -12,9 +12,12 @@
*/
package de.bixilon.minosoft.data.scoreboard
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreTeamChangeEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
class ScoreboardManager {
class ScoreboardManager(private val connection: PlayConnection) {
val teams: MutableMap<String, Team> = synchronizedMapOf()
val objectives: MutableMap<String, ScoreboardObjective> = synchronizedMapOf()
@ -24,7 +27,7 @@ class ScoreboardManager {
fun getTeamsOf(member: String): Set<Team> {
val teams: MutableSet<Team> = mutableSetOf()
for ((name, team) in this.teams) {
for ((_, team) in this.teams) {
if (!team.members.contains(member)) {
continue
}
@ -34,15 +37,19 @@ class ScoreboardManager {
return teams
}
fun updateScoreTeams(team: Team, members: Set<String>, remove: Boolean = false) {
for ((_, objective) in objectives) {
for ((_, score) in objective.scores) {
fun updateScoreTeams(team: Team, members: Set<String>, remove: Boolean = false, fireEvent: Boolean = true) {
for ((_, objective) in objectives.toSynchronizedMap()) {
for ((_, score) in objective.scores.toSynchronizedMap()) {
if (score.entity in members) {
if (remove) {
score.teams -= team
} else {
score.teams += team
}
if (!fireEvent) {
continue
}
connection.fireEvent(ScoreTeamChangeEvent(connection, objective, score, team, remove))
}
}
}

View File

@ -14,11 +14,17 @@ package de.bixilon.minosoft.data.scoreboard
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.objective.CreateScoreboardObjectiveS2CP
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
class ScoreboardObjective(
val name: String,
var displayName: ChatComponent,
var unit: CreateScoreboardObjectiveS2CP.ObjectiveUnits,
) {
val scores: MutableMap<String, ScoreboardScore> = mutableMapOf()
val scores: MutableMap<String, ScoreboardScore> = synchronizedMapOf()
override fun toString(): String {
return name
}
}

View File

@ -4,9 +4,10 @@ import de.bixilon.minosoft.util.KUtil
import de.bixilon.minosoft.util.enum.ValuesEnum
enum class ScoreboardPositions {
LIST,
TAB_LIST,
SIDEBAR,
BELOW_NAME,
TEAM_BLACK,
TEAM_DARK_BLUE,
TEAM_DARK_GREEN,

View File

@ -121,12 +121,13 @@ abstract class Element(val hudRenderer: HUDRenderer) {
* @return The number of z layers used
*/
fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
val offset = Vec2i(offset)
if (RenderConstants.DISABLE_GUI_CACHE || !cacheEnabled) {
return forceRender(offset, z, consumer, options)
}
if (!cacheUpToDate || cache.offset != offset || hudRenderer.matrixChange || cache.matrix !== hudRenderer.matrix || z != cache.z) {
val cache = GUIMeshCache(hudRenderer.matrix)
cache.offset = offset
cache.offset = Vec2i(offset)
cache.z = z
val maxZ = forceRender(offset, z, cache, options)
cache.maxZ = maxZ

View File

@ -89,7 +89,7 @@ open class RowLayout(
if (exceedsY(childSize.y)) {
break
}
val childZ = child.render(Vec2i(offset.x + margin.left + childAlignment.getOffset(size.x - margin.horizontal, childSize.x), offset.y + childYOffset), z, consumer, options)
val childZ = child.render(offset + Vec2i(margin.left + childAlignment.getOffset(size.x - margin.horizontal, childSize.x), childYOffset), z, consumer, options)
if (maxZ < childZ) {
maxZ = childZ
}

View File

@ -58,7 +58,7 @@ class TextFlowElement(
yOffset += Font.TOTAL_CHAR_HEIGHT
}
background.render(Vec2i(offset), z, consumer, options)
background.render(offset, z, consumer, options)
return LAYERS
}

View File

@ -34,6 +34,7 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.BreakProgressHUD
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.CrosshairHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.DebugHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.other.WorldInfoHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard.ScoreboardHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.tab.TabListHUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleHUDElement
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
@ -104,6 +105,7 @@ class HUDRenderer(
registerElement(HotbarHUDElement)
registerElement(WorldInfoHUDElement)
registerElement(TitleHUDElement)
registerElement(ScoreboardHUDElement)
}
override fun init() {

View File

@ -0,0 +1,69 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.scoreboard.ScoreboardPositions
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.HUDBuilder
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedHUDElement
import de.bixilon.minosoft.modding.event.events.scoreboard.*
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamUpdateEvent
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import glm_.vec2.Vec2i
class ScoreboardHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<ScoreboardSideElement>(hudRenderer) {
private val connection = hudRenderer.connection
override val layout = ScoreboardSideElement(hudRenderer)
override val layoutOffset: Vec2i
get() = Vec2i(hudRenderer.scaledSize.x - layout.size.x, (hudRenderer.scaledSize.y - layout.size.y) / 2)
override fun init() {
connection.registerEvent(CallbackEventInvoker.of<ObjectivePositionSetEvent> {
if (it.position != ScoreboardPositions.SIDEBAR) {
return@of
}
layout.objective = it.objective
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardObjectiveUpdateEvent> {
if (it.objective != layout.objective) {
return@of
}
layout.updateName()
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScoreRemoveEvent> {
if (it.score.objective != layout.objective) {
return@of
}
layout.removeScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreboardScorePutEvent> {
if (it.score.objective != layout.objective) {
return@of
}
layout.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<ScoreTeamChangeEvent> {
val objective = layout.objective ?: return@of
layout.updateScore(it.score)
})
connection.registerEvent(CallbackEventInvoker.of<TeamUpdateEvent> {
val objective = layout.objective ?: return@of
for ((_, score) in objective.scores) {
if (it.team !in score.teams) {
continue
}
layout.updateScore(score)
}
})
}
companion object : HUDBuilder<ScoreboardHUDElement> {
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:scoreboard".toResourceLocation()
override fun build(hudRenderer: HUDRenderer): ScoreboardHUDElement {
return ScoreboardHUDElement(hudRenderer)
}
}
}

View File

@ -0,0 +1,76 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
import de.bixilon.minosoft.data.scoreboard.ScoreboardScore
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i
class ScoreboardScoreElement(
hudRenderer: HUDRenderer,
val score: ScoreboardScore,
parent: Element?,
) : Element(hudRenderer) {
private val nameElement = TextElement(hudRenderer, "", background = false, parent = this)
private val scoreElement = TextElement(hudRenderer, "", background = false, parent = this)
init {
nameElement.prefMaxSize = Vec2i(-1, ScoreboardSideElement.SCORE_HEIGHT)
scoreElement.prefMaxSize = Vec2i(-1, ScoreboardSideElement.SCORE_HEIGHT)
forceSilentApply()
_parent = parent
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
nameElement.render(offset, z, consumer, options)
scoreElement.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, scoreElement.size.x), 0), z, consumer, options)
return TextElement.LAYERS
}
override fun silentApply(): Boolean {
forceSilentApply()
return true
}
override fun forceSilentApply() {
val name = BaseComponent()
// ToDo: Can a score (entity; whatever) can have multiple teams?
score.teams.iterator().apply {
if (!hasNext()) {
return@apply
}
val team = next()
name += team.prefix
name += team.suffix
}
name += score.entity
nameElement.text = name
scoreElement.text = TextComponent(score.value).color(ChatColors.RED)
_prefSize = Vec2i(nameElement.size.x + scoreElement.size.x + SCORE_MIN_MARGIN, ScoreboardSideElement.SCORE_HEIGHT)
cacheUpToDate = false
}
fun applySize() {
_size = parent?.size?.let { return@let Vec2i(it.x, ScoreboardSideElement.SCORE_HEIGHT) } ?: _prefSize
}
override fun onChildChange(child: Element) = Unit
companion object {
private const val SCORE_MIN_MARGIN = 5
}
}

View File

@ -0,0 +1,118 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
import de.bixilon.minosoft.data.scoreboard.ScoreboardObjective
import de.bixilon.minosoft.data.scoreboard.ScoreboardScore
import de.bixilon.minosoft.gui.rendering.RenderConstants
import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.util.vec.Vec2Util.EMPTY
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import glm_.vec2.Vec2i
class ScoreboardSideElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
private val backgroundElement = ColorElement(hudRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameBackgroundElement = ColorElement(hudRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameElement = TextElement(hudRenderer, "", background = false, parent = this)
private val scores: MutableMap<ScoreboardScore, ScoreboardScoreElement> = synchronizedMapOf()
var objective: ScoreboardObjective? = null
set(value) {
if (field == value) {
return
}
field = value
scores.clear()
forceSilentApply()
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
recalculateSize()
backgroundElement.render(offset, z, consumer, options)
nameBackgroundElement.render(offset, z + 1, consumer, options)
nameElement.render(offset + Vec2i(HorizontalAlignments.CENTER.getOffset(size.x, nameElement.size.x), 0), z + 2, consumer, options)
offset.y += Font.TOTAL_CHAR_HEIGHT
val scores = scores.toSynchronizedMap().toSortedMap { a, b -> b.value - a.value }
for ((_, score) in scores) {
score.render(offset, z + 2, consumer, options)
offset.y += score.size.y
}
return TextElement.LAYERS + 2 // 2 backgrounds
}
override fun forceSilentApply() {
val objective = objective
if (objective == null) {
_size = Vec2i.EMPTY
return
}
this.scores.clear()
updateName()
queueSizeRecalculation()
}
private fun recalculateSize() {
val size = Vec2i(MIN_WIDTH, Font.TOTAL_CHAR_HEIGHT)
size.x = maxOf(size.x, nameElement.size.x)
val scores = scores.toSynchronizedMap()
for ((_, element) in scores) {
element.forceSilentApply()
size.x = maxOf(size.x, element.prefSize.x)
}
size.y += SCORE_HEIGHT * scores.size
_size = size
nameBackgroundElement.size = Vec2i(size.x, SCORE_HEIGHT)
backgroundElement.size = size
for ((_, element) in scores) {
element.applySize()
}
}
@Synchronized
private fun queueSizeRecalculation() {
cacheUpToDate = false
}
fun removeScore(score: ScoreboardScore) {
scores.remove(score) ?: return
queueSizeRecalculation()
}
fun updateScore(score: ScoreboardScore) {
scores.getOrPut(score) { ScoreboardScoreElement(hudRenderer, score, this) }
queueSizeRecalculation()
}
fun updateName() {
nameElement.text = objective?.displayName ?: return
queueSizeRecalculation()
}
companion object {
const val MIN_WIDTH = 30
const val SCORE_HEIGHT = Font.TOTAL_CHAR_HEIGHT
}
}

View File

@ -51,7 +51,7 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
)
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
background.render(Vec2i(offset), z, consumer, options)
background.render(offset, z, consumer, options)
offset += BACKGROUND_PADDING
val size = size
@ -71,7 +71,7 @@ class TabListElement(hudRenderer: HUDRenderer) : Element(hudRenderer) {
}
for ((index, entry) in toRender.withIndex()) {
entry.render(Vec2i(offset), z + 1, consumer, options)
entry.render(offset, z + 1, consumer, options)
offset.y += TabListEntryElement.HEIGHT + ENTRY_VERTICAL_SPACING
if ((index + 1) % ENTRIES_PER_COLUMN == 0) {
offset.x += entry.width + ENTRY_HORIZONTAL_SPACING

View File

@ -72,8 +72,8 @@ class TabListEntryElement(
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
background.render(Vec2i(offset), z, consumer, options)
nameElement.render(Vec2i(offset), z, consumer, options)
background.render(offset, z, consumer, options)
nameElement.render(offset, z, consumer, options)
pingElement.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(maxSize.x, pingElement.size.x + PADDING), PADDING), z + 1, consumer, options)
return TextElement.LAYERS

View File

@ -0,0 +1,15 @@
package de.bixilon.minosoft.modding.event.events.scoreboard
import de.bixilon.minosoft.data.scoreboard.ScoreboardObjective
import de.bixilon.minosoft.data.scoreboard.ScoreboardScore
import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class ScoreTeamChangeEvent(
connection: PlayConnection,
val objective: ScoreboardObjective,
val score: ScoreboardScore,
val team: Team,
val remove: Boolean,
) : PlayConnectionEvent(connection)

View File

@ -1,10 +1,10 @@
package de.bixilon.minosoft.modding.event.events.scoreboard
package de.bixilon.minosoft.modding.event.events.scoreboard.team
import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class ScoreboardTeamCreateEvent(
class TeamCreateEvent(
connection: PlayConnection,
val team: Team,
) : PlayConnectionEvent(connection)

View File

@ -1,9 +1,10 @@
package de.bixilon.minosoft.modding.event.events.scoreboard
package de.bixilon.minosoft.modding.event.events.scoreboard.team
import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardTeamMemberEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class ScoreboardTeamMemberAddEvent(
class TeamMemberAddEvent(
connection: PlayConnection,
team: Team,
members: Set<String>,

View File

@ -1,9 +1,10 @@
package de.bixilon.minosoft.modding.event.events.scoreboard
package de.bixilon.minosoft.modding.event.events.scoreboard.team
import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardTeamMemberEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class ScoreboardTeamMemberRemoveEvent(
class TeamMemberRemoveEvent(
connection: PlayConnection,
team: Team,
members: Set<String>,

View File

@ -0,0 +1,10 @@
package de.bixilon.minosoft.modding.event.events.scoreboard.team
import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class TeamUpdateEvent(
connection: PlayConnection,
val team: Team,
) : PlayConnectionEvent(connection)

View File

@ -71,7 +71,7 @@ class PlayConnection(
val recipes = Recipes()
val world = World(this)
val tabList = TabList()
val scoreboardManager = ScoreboardManager()
val scoreboardManager = ScoreboardManager(this)
val bossbarManager = BossbarManager()
@Deprecated(message = "PacketSender is deprecated")

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.objective
import de.bixilon.minosoft.modding.event.events.scoreboard.ObjectivePositionSetEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
@ -35,6 +36,7 @@ class RemoveScoreboardObjectiveS2CP(val objective: String, buffer: PlayInByteBuf
continue
}
connection.scoreboardManager.positions -= position
connection.fireEvent(ObjectivePositionSetEvent(connection, position, null))
}
}
}

View File

@ -17,6 +17,7 @@ import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardScoreRemove
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
@ -24,7 +25,14 @@ import de.bixilon.minosoft.util.logging.LogMessageType
class RemoveScoreboardScoreS2CP(val entity: String, val objective: String?, buffer: PlayInByteBuffer) : PlayS2CPacket() {
override fun handle(connection: PlayConnection) {
val objective = connection.scoreboardManager.objectives[objective] ?: return
val objective = connection.scoreboardManager.objectives[objective] ?: let {
for ((_, objective) in connection.scoreboardManager.objectives.toSynchronizedMap()) {
val score = objective.scores.remove(entity) ?: continue
connection.fireEvent(ScoreboardScoreRemoveEvent(connection, score))
}
return
}
val score = objective.scores.remove(entity) ?: return
connection.fireEvent(ScoreboardScoreRemoveEvent(connection, score))

View File

@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.scoreboard.Team
import de.bixilon.minosoft.data.scoreboard.TeamCollisionRules
import de.bixilon.minosoft.data.text.ChatCode
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardTeamCreateEvent
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamCreateEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
@ -123,7 +123,7 @@ class TeamCreateS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPacket
connection.scoreboardManager.updateScoreTeams(team, members)
connection.fireEvent(ScoreboardTeamCreateEvent(connection, team))
connection.fireEvent(TeamCreateEvent(connection, team))
}
override fun log() {

View File

@ -14,7 +14,7 @@
package de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.teams
import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardTeamMemberAddEvent
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamMemberAddEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
@ -41,7 +41,7 @@ class TeamMemberAddS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPac
}
connection.scoreboardManager.updateScoreTeams(team, members)
connection.fireEvent(ScoreboardTeamMemberAddEvent(connection, team, members))
connection.fireEvent(TeamMemberAddEvent(connection, team, members))
}
override fun log() {

View File

@ -13,7 +13,7 @@
package de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.teams
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreboardTeamMemberRemoveEvent
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamMemberRemoveEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
@ -44,7 +44,7 @@ class TeamMemberRemoveS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2C
}
connection.scoreboardManager.updateScoreTeams(team, members, true)
connection.fireEvent(ScoreboardTeamMemberRemoveEvent(connection, team, members))
connection.fireEvent(TeamMemberRemoveEvent(connection, team, members))
}
override fun log() {

View File

@ -18,6 +18,7 @@ import de.bixilon.minosoft.data.scoreboard.NameTagVisibilities
import de.bixilon.minosoft.data.scoreboard.TeamCollisionRules
import de.bixilon.minosoft.data.text.ChatCode
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.modding.event.events.scoreboard.team.TeamUpdateEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
@ -91,16 +92,18 @@ class TeamUpdateS2CP(val name: String, buffer: PlayInByteBuffer) : PlayS2CPacket
override fun handle(connection: PlayConnection) {
connection.scoreboardManager.teams[name]?.let {
it.displayName = displayName
it.prefix = prefix
it.suffix = suffix
it.friendlyFire = friendlyFire
it.canSeeInvisibleTeam = canSeeInvisibleTeam
it.collisionRule = collisionRule
it.nameTagVisibility = nameTagVisibility
it.formattingCode = formattingCode
}
val team = connection.scoreboardManager.teams[name] ?: return
team.displayName = displayName
team.prefix = prefix
team.suffix = suffix
team.friendlyFire = friendlyFire
team.canSeeInvisibleTeam = canSeeInvisibleTeam
team.collisionRule = collisionRule
team.nameTagVisibility = nameTagVisibility
team.formattingCode = formattingCode
connection.fireEvent(TeamUpdateEvent(connection, team))
}
override fun log() {

View File

@ -231,17 +231,17 @@ class PacketTypes {
PLAY_CAMERA({ CameraS2CP(it) }),
PLAY_HOTBAR_SLOT_SET({ HotbarSlotSetS2CP(it) }),
PLAY_CHUNK_CENTER_SET({ ChunkCenterSetS2CP(it) }),
PLAY_OBJECTIVE_POSITION_SET({ ObjectivePositionSetS2CP(it) }),
PLAY_OBJECTIVE_POSITION_SET({ ObjectivePositionSetS2CP(it) }, isThreadSafe = false),
PLAY_ENTITY_METADATA({ EntityMetadataS2CP(it) }, isThreadSafe = false),
PLAY_ENTITY_ATTACH({ EntityAttachS2CP(it) }),
PLAY_ENTITY_VELOCITY({ EntityVelocityS2CP(it) }),
PLAY_ENTITY_EQUIPMENT({ EntityEquipmentS2CP(it) }),
PLAY_EXPERIENCE_SET({ ExperienceSetS2CP(it) }),
PLAY_HEALTH_SET({ HealthSetS2CP(it) }),
PLAY_SCOREBOARD_OBJECTIVE({ ScoreboardObjectiveS2CF.createPacket(it) }),
PLAY_SCOREBOARD_OBJECTIVE({ ScoreboardObjectiveS2CF.createPacket(it) }, isThreadSafe = false),
PLAY_ENTITY_PASSENGER_SET({ EntityPassengerSetS2CP(it) }),
PLAY_TEAMS({ TeamsS2CF.createPacket(it) }),
PLAY_UPDATE_SCORE({ ScoreboardScoreS2CF.createPacket(it) }),
PLAY_UPDATE_SCORE({ ScoreboardScoreS2CF.createPacket(it) }, isThreadSafe = false),
PLAY_COMPASS_POSITION_SET({ CompassPositionSetS2CP(it) }),
PLAY_WORLD_TIME_SET({ WorldTimeSetS2CP(it) }),
PLAY_ENTITY_SOUND_EVENT({ EntitySoundEventS2CP(it) }),

View File

@ -95,16 +95,21 @@ object KUtil {
return Collections.synchronizedList(mutableListOf(*values))
}
private fun <K> Any.synchronizedCopy(copier: () -> K): K {
private fun <K> Any.synchronizedCopy(lock: Object? = null, copier: () -> K): K {
val ret: K
synchronized(this) {
synchronized(lock ?: this) {
ret = copier()
}
return ret
}
fun <K, V> Map<K, V>.toSynchronizedMap(): SynchronizedMap<K, V> {
return synchronizedCopy { SynchronizedMap(this.toMutableMap()) }
val lock = if (this is SynchronizedMap<*, *>) {
this.lock
} else {
null
}
return synchronizedCopy(lock) { SynchronizedMap(this.toMutableMap()) }
}
fun <V> Collection<V>.toSynchronizedList(): MutableList<V> {

View File

@ -22,7 +22,7 @@ import java.util.function.Function
class SynchronizedMap<K, V>(
private val original: MutableMap<K, V>,
) : MutableMap<K, V> {
private val lock = Object()
internal val lock = Object()
override val size: Int
get() = synchronized(lock) { original.size }