Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement state machine to model game state #256

Draft
wants to merge 52 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7946103
feat: add phase components representing states
jdrueckert Nov 21, 2021
518119f
feat: add phase system to manage state machine
jdrueckert Nov 21, 2021
68a0772
feat: add notification events for completed state transitions
jdrueckert Nov 21, 2021
ffb5e6b
feat: add intermediate changes
jdrueckert Dec 17, 2021
bc81fae
rename `statemachine` package to `phases`
skaldarnar Dec 17, 2021
82c2a48
get all the things up to speed again
skaldarnar Dec 17, 2021
df60b2f
Merge remote-tracking branch 'origin/develop' into feat/state-machine
skaldarnar Dec 17, 2021
e467dff
refactor: fix naming for in-game phase started event
jdrueckert Dec 17, 2021
6b7eab6
refactor: simplify phase transitions
jdrueckert Dec 17, 2021
13cc215
fix: phase transition command
jdrueckert Dec 17, 2021
808f2c0
fix: phase transition command test
jdrueckert Dec 17, 2021
912ac04
test: add negative forcePhase command test for non-enum target phase
jdrueckert Dec 17, 2021
44c23a9
introduce PhaseParameterAdapter to allow for `Phase` instances as com…
skaldarnar Dec 18, 2021
baf45c9
improve PhaseCommandsSystem and register parameter adapter
skaldarnar Dec 18, 2021
3998e12
fix checkstyle issues
skaldarnar Dec 18, 2021
9ec8aba
feat: add SwitchToPhaseEvent for systems to trigger phase transition
jdrueckert Aug 31, 2022
0d4581f
refactor: split up PregameSystem on AttackSystem and MagicDomeSystem
jdrueckert Aug 31, 2022
f40653c
feat: switch to Pre-Game Phase on first player joining game
jdrueckert Aug 31, 2022
9bee4be
feat: add LASTeamStatsComponent to game entity to track team sizes
jdrueckert Aug 31, 2022
00e2335
feat: make minimum team size configurable
jdrueckert Aug 31, 2022
234f7f3
refactor: split out teleport and game start condition checks, leverag…
jdrueckert Aug 31, 2022
d93de23
refactor: replace gameStart bool with phase check and transition
jdrueckert Aug 31, 2022
7f3514c
feat: add command to set min team size
jdrueckert Aug 31, 2022
75f2274
refactor: pregame client message
jdrueckert Aug 31, 2022
840dc48
feat: replace client pregame screen message with notification
jdrueckert Aug 31, 2022
67a0ea9
chore: reduce notification text lengths
jdrueckert Aug 31, 2022
8e48b4d
fix: Broadcast event not broadcasting due to missing Network component
jdrueckert Sep 22, 2022
84bf592
chore: remove unnecessary imports
jdrueckert Sep 22, 2022
447122f
refactor: move duplicated notification helper into LASUtils
jdrueckert Sep 23, 2022
c2a7cf1
chore: update team stats directly before stat-based checks
jdrueckert Sep 23, 2022
4f839df
feat: show notification for new players and expire it on phase end
jdrueckert Sep 23, 2022
1427864
refactor: extract client shop logic into new ClientShopSystem
jdrueckert Sep 25, 2022
ecc6b87
refactor: rename ClientPregameSystem -> ClientGameStateInfoSystem
jdrueckert Sep 30, 2022
2a39f51
feat: restrict conditions in which barrier effect is applied
jdrueckert Oct 2, 2022
75a4d42
feat: add cmd to teleport back to platform
jdrueckert Oct 2, 2022
238b610
refactor: extract team-related helpers into new TeamSystem
jdrueckert Oct 23, 2022
013b342
feat: add cleanup actions on arena exit
jdrueckert Oct 23, 2022
6ffee54
refactor: let TeamSystem handle adding player to team
jdrueckert Oct 23, 2022
ae24b83
feat: always spawn players on platform
jdrueckert Oct 23, 2022
bffd298
refactor: rename ClientGameStateInfoSystem to ClientInformationSystem
jdrueckert Oct 23, 2022
0e12a66
refactor: merge ClientStatisticsSystem into ClientInformationSystem
jdrueckert Oct 23, 2022
806f18d
feat: cancel timer if no longer countdown phase, switch to in-game ph…
jdrueckert Oct 23, 2022
a1eae07
feat: remove barriers on phase switch PreGame -> InGame
jdrueckert Oct 23, 2022
1af8171
feat: switch to postGame phase once one team won
jdrueckert Oct 23, 2022
072b5c1
feat: switch to preGame phase on restart request
jdrueckert Oct 23, 2022
4ed4709
refactor: merge ClientGameOverSystem into ClientInformationSystem
jdrueckert Oct 23, 2022
470ee3d
refactor: merge ClientRestartSystem into ClientInformationSystem
jdrueckert Oct 23, 2022
eeedd5c
refactor: merge ClientScoreSystem into ClientInformationSystem
jdrueckert Oct 23, 2022
5c025a2
fix: share TeamSystem to inject it in TeleporterSystem
jdrueckert Nov 3, 2022
171b29a
fix: owner of player entity has ClientComponent, not player entity it…
jdrueckert Nov 3, 2022
25b7d6e
refactor: arena exit clean up actions
jdrueckert Nov 6, 2022
d93ea07
feat: expire "too few players" notification when no more players in a…
jdrueckert Nov 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion assets/prefabs/gameEntity.prefab
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"LASConfig" : {
"maxTeamSizeDifference" : 3
"maxTeamSizeDifference": 3,
"minTeamSize": 1
},
"CurrencyStorage": {
"amount": 100
},
// this component is required for the PhaseSystem phase change events to be broadcasted
"Network": {
"replicateMode": "ALWAYS"
}
}
37 changes: 37 additions & 0 deletions src/main/java/org/terasology/module/lightandshadow/LASUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.terasology.engine.core.SimpleUri;
import org.terasology.engine.unicode.EnclosedAlphanumerics;
import org.terasology.engine.input.InputSystem;
import org.terasology.input.Input;
import org.terasology.nui.Color;
import org.terasology.nui.FontColor;

import static java.util.Collections.singletonMap;

public final class LASUtils {
Expand Down Expand Up @@ -222,4 +229,34 @@ public static String pixel(int x, int y, int r) {
.findAny()
.orElse("engine:air");
}

/**
* Get a formatted representation of the primary {@link Input} associated with the given button binding.
*
* If the display name of the primary bound key is a single character this representation will be the encircled
* character. Otherwise the full display name is used. The bound key will be printed in yellow.
*
* If no key binding was found the text "n/a" in red color is returned.
*
* @param button the URI of a bindable button
* @return a formatted text to be used as representation for the player
*/
//TODO: put this in a common place? Duplicated in Dialogs, EventualSkills, and InGameHelp
public static String getActivationKey(InputSystem inputSystem, SimpleUri button) {
return inputSystem.getInputsForBindButton(button).stream()
.findFirst()
.map(Input::getDisplayName)
.map(key -> {
if (key.length() == 1) {
// print the key in yellow within a circle
int off = key.charAt(0) - 'A';
char code = (char) (EnclosedAlphanumerics.CIRCLED_LATIN_CAPITAL_LETTER_A + off);
return String.valueOf(code);
} else {
return key;
}
})
.map(key -> FontColor.getColored(key, Color.yellow))
.orElse(FontColor.getColored("n/a", Color.red));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

public class LASConfigComponent implements Component<LASConfigComponent> {
public int maxTeamSizeDifference;
public int minTeamSize;

@Override
public void copyFrom(LASConfigComponent other) {
this.maxTeamSizeDifference = other.maxTeamSizeDifference;
this.minTeamSize = other.minTeamSize;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2022 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.components;

import org.terasology.gestalt.entitysystem.component.Component;

public class LASTeamStatsComponent implements Component<LASTeamStatsComponent> {
public int redTeamSize;
public int blackTeamSize;
public int whiteTeamSize;

@Override
public void copyFrom(LASTeamStatsComponent other) {
this.blackTeamSize = other.blackTeamSize;
this.redTeamSize = other.redTeamSize;
this.whiteTeamSize = other.whiteTeamSize;
}

}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2022 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.events;

import org.terasology.engine.entitySystem.entity.EntityRef;
import org.terasology.gestalt.entitysystem.event.Event;

public class PlayerExitedArenaEvent implements Event {
private final EntityRef player;

public PlayerExitedArenaEvent(EntityRef player) {
this.player = player;
}

public EntityRef getPlayer() {
return player;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnCountdownPhaseEndedEvent implements Event {

public OnCountdownPhaseEndedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnCountdownPhaseStartedEvent implements Event {

public OnCountdownPhaseStartedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnIdlePhaseEndedEvent implements Event {

public OnIdlePhaseEndedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnIdlePhaseStartedEvent implements Event {

public OnIdlePhaseStartedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnInGamePhaseEndedEvent implements Event {

public OnInGamePhaseEndedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnInGamePhaseStartedEvent implements Event {

public OnInGamePhaseStartedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnPostGamePhaseEndedEvent implements Event {

public OnPostGamePhaseEndedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnPostGamePhaseStartedEvent implements Event {

public OnPostGamePhaseStartedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnPreGamePhaseEndedEvent implements Event {

public OnPreGamePhaseEndedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.engine.network.BroadcastEvent;
import org.terasology.gestalt.entitysystem.event.Event;

// TODO: Would it make more sense to have a single "OnPhaseTransition" with old and new phase here?

@BroadcastEvent
public class OnPreGamePhaseStartedEvent implements Event {

public OnPreGamePhaseStartedEvent() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.module.lightandshadow.phases;

import org.terasology.gestalt.entitysystem.event.Event;

import java.util.function.Supplier;

public enum Phase {
IDLE(OnIdlePhaseStartedEvent::new, OnIdlePhaseEndedEvent::new),
PRE_GAME(OnPreGamePhaseStartedEvent::new, OnPreGamePhaseEndedEvent::new),
COUNTDOWN(OnCountdownPhaseStartedEvent::new, OnCountdownPhaseEndedEvent::new),
IN_GAME(OnInGamePhaseStartedEvent::new, OnInGamePhaseEndedEvent::new),
POST_GAME(OnPostGamePhaseStartedEvent::new, OnPostGamePhaseEndedEvent::new);

public final Supplier<Event> endEvent;
public final Supplier<Event> startEvent;

Phase(Supplier<Event> startEvent, Supplier<Event> endEvent) {
this.startEvent = startEvent;
this.endEvent = endEvent;
}
}
Loading