properly synchronized scoreboard, fix other scoreboard bugs

This commit is contained in:
Bixilon 2022-06-16 16:06:01 +02:00
parent 7cb84304d0
commit f10abc3d69
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
3 changed files with 35 additions and 16 deletions

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -12,32 +12,38 @@
*/
package de.bixilon.minosoft.data.scoreboard
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.kutil.collections.map.LockMap
import de.bixilon.kutil.primitive.BooleanUtil.decide
import de.bixilon.minosoft.modding.event.events.scoreboard.ScoreTeamChangeEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class ScoreboardManager(private val connection: PlayConnection) {
val teams: MutableMap<String, Team> = synchronizedMapOf()
val objectives: MutableMap<String, ScoreboardObjective> = synchronizedMapOf()
val teams: LockMap<String, Team> = lockMapOf()
val objectives: LockMap<String, ScoreboardObjective> = lockMapOf()
val positions: MutableMap<ScoreboardPositions, ScoreboardObjective> = synchronizedMapOf()
fun getTeam(member: String): Team? {
for ((_, team) in this.teams.toSynchronizedMap()) {
this.teams.lock.acquire()
for (team in this.teams.values) {
if (member !in team.members) {
continue
}
this.teams.lock.release()
return team
}
this.teams.lock.release()
return null
}
fun updateScoreTeams(team: Team, members: Set<String>, remove: Boolean = false, fireEvent: Boolean = true) {
for ((_, objective) in objectives.toSynchronizedMap()) {
for ((_, score) in objective.scores.toSynchronizedMap()) {
objectives.lock.acquire()
for (objective in objectives.values) {
objective.scores.lock.acquire()
for (score in objective.scores.values) {
if (score.entity in members) {
score.team = remove.decide(null, team)
if (!fireEvent) {
@ -46,6 +52,8 @@ class ScoreboardManager(private val connection: PlayConnection) {
connection.fireEvent(ScoreTeamChangeEvent(connection, objective, score, team, remove))
}
}
objective.scores.lock.release()
}
objectives.lock.release()
}
}

View File

@ -12,7 +12,8 @@
*/
package de.bixilon.minosoft.data.scoreboard
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
import de.bixilon.kutil.collections.map.LockMap
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.objective.CreateObjectiveS2CP
@ -21,7 +22,7 @@ class ScoreboardObjective(
var displayName: ChatComponent,
var unit: CreateObjectiveS2CP.ObjectiveUnits,
) {
val scores: MutableMap<String, ScoreboardScore> = synchronizedMapOf()
val scores: LockMap<String, ScoreboardScore> = lockMapOf()
override fun toString(): String {

View File

@ -14,8 +14,9 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements.scoreboard
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.kutil.collections.map.LockMap
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.scoreboard.ScoreboardObjective
import de.bixilon.minosoft.data.scoreboard.ScoreboardPositions
@ -45,7 +46,7 @@ class ScoreboardSideElement(guiRenderer: GUIRenderer) : Element(guiRenderer), La
private val backgroundElement = ColorElement(guiRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameBackgroundElement = ColorElement(guiRenderer, size = Vec2i.EMPTY, color = RenderConstants.TEXT_BACKGROUND_COLOR)
private val nameElement = TextElement(guiRenderer, "", background = false, parent = this)
private val scores: MutableMap<ScoreboardScore, ScoreboardScoreElement> = synchronizedMapOf()
private val scores: LockMap<ScoreboardScore, ScoreboardScoreElement> = lockMapOf()
override val layoutOffset: Vec2i
get() = super.size.let { return@let Vec2i(guiRenderer.scaledSize.x - it.x, (guiRenderer.scaledSize.y - it.y) / 2) }
@ -74,11 +75,14 @@ class ScoreboardSideElement(guiRenderer: GUIRenderer) : Element(guiRenderer), La
nameElement.render(offset + Vec2i(HorizontalAlignments.CENTER.getOffset(size.x, nameElement.size.x), 0), consumer, options)
offset.y += Font.TOTAL_CHAR_HEIGHT
val scores = scores.toSynchronizedMap().entries.sortedWith { a, b -> a.key.compareTo(b.key) }
this.scores.lock.acquire()
val scores = this.scores.unsafe.entries.sortedWith { a, b -> a.key.compareTo(b.key) }
this.scores.lock.release()
var index = 0
for ((_, score) in scores) {
score.render(offset, consumer, options)
offset.y += score.size.y
offset.y += Font.TOTAL_CHAR_HEIGHT
if (++index >= MAX_SCORES) {
break
@ -93,7 +97,14 @@ class ScoreboardSideElement(guiRenderer: GUIRenderer) : Element(guiRenderer), La
return
}
this.scores.clear()
this.scores.lock.lock()
this.scores.unsafe.clear()
objective.scores.lock.acquire()
for (score in objective.scores.values) {
this.scores.unsafe.getOrPut(score) { ScoreboardScoreElement(guiRenderer, score, this) }
}
objective.scores.lock.release()
this.scores.lock.unlock()
updateName()
@ -131,7 +142,6 @@ class ScoreboardSideElement(guiRenderer: GUIRenderer) : Element(guiRenderer), La
}
}
@Synchronized
private fun queueSizeRecalculation() {
cacheUpToDate = false
}
@ -142,7 +152,7 @@ class ScoreboardSideElement(guiRenderer: GUIRenderer) : Element(guiRenderer), La
}
fun updateScore(score: ScoreboardScore) {
scores.getOrPut(score) { ScoreboardScoreElement(guiRenderer, score, this) }
scores.synchronizedGetOrPut(score) { ScoreboardScoreElement(guiRenderer, score, this) }
queueSizeRecalculation()
}