Client & network general improvement
This commit is contained in:
@@ -17,6 +17,10 @@ export default {
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
},
|
},
|
||||||
|
camera: {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
},
|
||||||
renderTimer: null
|
renderTimer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -34,7 +38,20 @@ export default {
|
|||||||
return this.$store.state.game.player
|
return this.$store.state.game.player
|
||||||
},
|
},
|
||||||
players () {
|
players () {
|
||||||
return this.$store.state.game.players
|
const pastUpdate = this.$store.state.game.updates[0]
|
||||||
|
const nextUpdate = this.$store.state.game.updates[1]
|
||||||
|
|
||||||
|
if (pastUpdate === undefined) return []
|
||||||
|
if (pastUpdate.players === undefined) return []
|
||||||
|
if (nextUpdate === undefined) return pastUpdate.players
|
||||||
|
|
||||||
|
return pastUpdate.players
|
||||||
|
|
||||||
|
/*
|
||||||
|
const currentTime = Date.now() / 1000
|
||||||
|
const dt = (currentTime - pastUpdate.time) / (nextUpdate.time - pastUpdate.time)
|
||||||
|
return pastUpdate.players.map(player => this.interpolatePlayer(player, nextUpdate.players.find(nextPlayer => player.color === nextPlayer.color), dt))
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
isPaused () {
|
isPaused () {
|
||||||
return this.$store.state.game.paused
|
return this.$store.state.game.paused
|
||||||
@@ -52,26 +69,28 @@ export default {
|
|||||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||||
this.renderBorders()
|
this.renderBorders()
|
||||||
|
|
||||||
|
if (!this.players) return
|
||||||
|
|
||||||
this.players.forEach(player => {
|
this.players.forEach(player => {
|
||||||
|
if (player.color === this.player.color) {
|
||||||
|
this.camera.x = player.x
|
||||||
|
this.camera.y = player.y
|
||||||
|
this.renderDebug(player)
|
||||||
|
}
|
||||||
this.renderPlayer(player)
|
this.renderPlayer(player)
|
||||||
this.renderWalls(player)
|
this.renderWalls(player)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.renderDebug(this.player)
|
|
||||||
|
|
||||||
// this.checkPlayerColision()
|
|
||||||
this.updatePlayer(this.player)
|
|
||||||
},
|
},
|
||||||
renderBorders () {
|
renderBorders () {
|
||||||
this.context.strokeStyle = 'black'
|
this.context.strokeStyle = 'black'
|
||||||
this.context.lineWidth = 1
|
this.context.lineWidth = 1
|
||||||
this.context.strokeRect(this.canvas.width / 2 - this.player.x, this.canvas.height / 2 - this.player.y, this.settings.arenaSize, this.settings.arenaSize)
|
this.context.strokeRect(this.canvas.width / 2 - this.camera.x, this.canvas.height / 2 - this.camera.y, this.settings.arenaSize, this.settings.arenaSize)
|
||||||
},
|
},
|
||||||
renderPlayer (player) {
|
renderPlayer (player) {
|
||||||
this.context.save()
|
this.context.save()
|
||||||
|
|
||||||
const canvasX = this.canvas.width / 2 + player.x - this.player.x
|
const canvasX = this.canvas.width / 2 + player.x - this.camera.x
|
||||||
const canvasY = this.canvas.height / 2 + player.y - this.player.y
|
const canvasY = this.canvas.height / 2 + player.y - this.camera.y
|
||||||
|
|
||||||
this.context.translate(canvasX, canvasY)
|
this.context.translate(canvasX, canvasY)
|
||||||
this.context.rotate(player.angle)
|
this.context.rotate(player.angle)
|
||||||
@@ -86,41 +105,16 @@ export default {
|
|||||||
this.context.lineWidth = this.settings.wallSize
|
this.context.lineWidth = this.settings.wallSize
|
||||||
this.context.strokeStyle = player.color
|
this.context.strokeStyle = player.color
|
||||||
player.walls.forEach(wall => {
|
player.walls.forEach(wall => {
|
||||||
const canvasX = this.canvas.width / 2 + wall.x - this.player.x
|
const canvasX = this.canvas.width / 2 + wall.x - this.camera.x
|
||||||
const canvasY = this.canvas.height / 2 + wall.y - this.player.y
|
const canvasY = this.canvas.height / 2 + wall.y - this.camera.y
|
||||||
this.context.lineTo(canvasX, canvasY)
|
this.context.lineTo(canvasX, canvasY)
|
||||||
})
|
})
|
||||||
this.context.lineTo(this.canvas.width / 2 + player.x - this.player.x, this.canvas.height / 2 + player.y - this.player.y)
|
this.context.lineTo(this.canvas.width / 2 + player.x - this.camera.x, this.canvas.height / 2 + player.y - this.camera.y)
|
||||||
this.context.stroke()
|
this.context.stroke()
|
||||||
},
|
},
|
||||||
renderDebug (player) {
|
renderDebug (player) {
|
||||||
const canvasX = this.canvas.width / 2
|
const canvasX = this.canvas.width / 2
|
||||||
const canvasY = this.canvas.height / 2
|
const canvasY = this.canvas.height / 2
|
||||||
/*
|
|
||||||
this.context.beginPath()
|
|
||||||
this.context.lineTo(canvasX, canvasY)
|
|
||||||
this.context.lineTo(this.mouse.x, this.mouse.y)
|
|
||||||
this.context.lineWidth = 1
|
|
||||||
this.context.strokeStyle = 'blue'
|
|
||||||
this.context.stroke()
|
|
||||||
|
|
||||||
const x = canvasX + 30 * Math.cos(player.angle) * 2
|
|
||||||
const y = canvasY + 30 * Math.sin(player.angle) * 2
|
|
||||||
this.context.beginPath()
|
|
||||||
this.context.lineTo(canvasX, canvasY)
|
|
||||||
this.context.lineTo(x, y)
|
|
||||||
this.context.lineWidth = 1
|
|
||||||
this.context.strokeStyle = 'yellow'
|
|
||||||
this.context.stroke()
|
|
||||||
|
|
||||||
const canvasX2 = this.canvas.width / 2
|
|
||||||
const canvasY2 = this.canvas.height / 2
|
|
||||||
this.context.beginPath()
|
|
||||||
this.context.arc(canvasX2, canvasY2, this.settings.playerSize, 0, 2 * Math.PI, false)
|
|
||||||
this.context.lineWidth = 1
|
|
||||||
this.context.strokeStyle = 'purple'
|
|
||||||
this.context.stroke()
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.context.fillText('player x: ' + player.x + ' y:' + player.y, 10, 10)
|
this.context.fillText('player x: ' + player.x + ' y:' + player.y, 10, 10)
|
||||||
this.context.fillText('a:' + player.angle + ' a_t' + player.targetAngle, 10, 20)
|
this.context.fillText('a:' + player.angle + ' a_t' + player.targetAngle, 10, 20)
|
||||||
@@ -152,17 +146,10 @@ export default {
|
|||||||
var dy = this.mouse.y - this.canvas.height / 2
|
var dy = this.mouse.y - this.canvas.height / 2
|
||||||
|
|
||||||
this.player.targetAngle = Math.atan2(dy, dx)
|
this.player.targetAngle = Math.atan2(dy, dx)
|
||||||
|
this.player.angle = this.player.targetAngle
|
||||||
send({ message: this.player, type: 'update' })
|
send({ message: this.player, type: 'update' })
|
||||||
},
|
},
|
||||||
updatePlayer (player) {
|
updatePlayer (player) {
|
||||||
/*
|
|
||||||
this.player.lastWall++
|
|
||||||
if (this.player.lastWall > this.settings.wallUpdate) {
|
|
||||||
this.player.walls.push({ x: this.player.x, y: this.player.y })
|
|
||||||
this.player.lastWall = 0
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
player.x += this.settings.playerSpeed * Math.cos(player.angle)
|
player.x += this.settings.playerSpeed * Math.cos(player.angle)
|
||||||
player.y += this.settings.playerSpeed * Math.sin(player.angle)
|
player.y += this.settings.playerSpeed * Math.sin(player.angle)
|
||||||
|
|
||||||
@@ -177,55 +164,19 @@ export default {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
},
|
},
|
||||||
checkPlayerColision () {
|
interpolatePlayer (pastPlayer, nextPlayer, dt) {
|
||||||
const playerX = this.player.x
|
var player = {}
|
||||||
const playerY = this.player.y
|
player.color = pastPlayer.color
|
||||||
// BORDERS
|
player.walls = pastPlayer.walls
|
||||||
if (playerX - this.settings.playerSize < 0 ||
|
player.lastWall = pastPlayer.lastWall
|
||||||
playerX + this.settings.playerSize > this.settings.arenaSize ||
|
|
||||||
playerY - this.settings.playerSize < 0 ||
|
|
||||||
playerY + this.settings.playerSize > this.settings.arenaSize
|
|
||||||
) {
|
|
||||||
this.context.fillText('DED BORDER', this.canvas.width / 2, this.canvas.height / 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WALLS
|
player.x = pastPlayer.x + (nextPlayer.x - pastPlayer.x) * dt
|
||||||
for (var i = 0; i < this.player.walls.length - 2; i++) {
|
player.y = pastPlayer.y + (nextPlayer.y - pastPlayer.y) * dt
|
||||||
const wallA = this.player.walls[i]
|
|
||||||
const wallB = this.player.walls[i + 1]
|
|
||||||
if (this.isCloseToWall(wallA.x, wallA.y, wallB.x, wallB.y, playerX, playerY, this.settings.playerSize)) {
|
|
||||||
if (this.isCrossingLine(wallA.x, wallA.y, wallB.x, wallB.y, playerX, playerY, this.settings.playerSize)) {
|
|
||||||
this.context.fillText('DED WALL OWN', this.canvas.width / 2, this.canvas.height / 2)
|
|
||||||
this.context.beginPath()
|
|
||||||
const canvasX = this.canvas.width / 2 + wallA.x - this.player.x
|
|
||||||
const canvasY = this.canvas.height / 2 + wallA.y - this.player.y
|
|
||||||
this.context.lineTo(canvasX, canvasY)
|
|
||||||
const canvasX2 = this.canvas.width / 2 + wallB.x - this.player.x
|
|
||||||
const canvasY2 = this.canvas.height / 2 + wallB.y - this.player.y
|
|
||||||
this.context.lineTo(canvasX2, canvasY2)
|
|
||||||
this.context.lineWidth = this.settings.wallSize
|
|
||||||
this.context.strokeStyle = 'purple'
|
|
||||||
this.context.stroke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isCloseToWall (xa, ya, xb, yb, xc, yc, radius) {
|
|
||||||
var xar = Math.min(xa, xb) - radius
|
|
||||||
var yar = Math.min(ya, yb) - radius
|
|
||||||
var xbr = Math.max(xa, xb) + radius
|
|
||||||
var ybr = Math.max(ya, yb) + radius
|
|
||||||
|
|
||||||
return ((xc >= xar && xc <= xbr) && (yc >= yar && yc <= ybr))
|
player.angle = pastPlayer.angle + (nextPlayer.angle - pastPlayer.angle) * dt
|
||||||
},
|
player.targetAngle = pastPlayer.targetAngle + (nextPlayer.targetAngle - pastPlayer.targetAngle) * dt
|
||||||
isCrossingLine (xa, ya, xb, yb, xc, yc, radius) {
|
|
||||||
var a = xc - xa
|
|
||||||
var b = xb - xa
|
|
||||||
var c = yc - ya
|
|
||||||
var d = yb - ya
|
|
||||||
var result = (a * d - b * c) / Math.sqrt(Math.pow(xa - xb, 2) + Math.pow(ya - yb, 2))
|
|
||||||
|
|
||||||
return result < radius
|
return player
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ const state = {
|
|||||||
targetAngle: 0,
|
targetAngle: 0,
|
||||||
color: 'red'
|
color: 'red'
|
||||||
},
|
},
|
||||||
players: {
|
updates: [],
|
||||||
|
|
||||||
},
|
|
||||||
settings: {
|
settings: {
|
||||||
playerSize: 10,
|
playerSize: 10,
|
||||||
playerSpeed: 2,
|
playerSpeed: 2,
|
||||||
@@ -22,11 +20,20 @@ const state = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
|
// Interpolation position des joueurs
|
||||||
|
currentPlayers: state => {
|
||||||
|
if (state.updates.length < 2) return state.updates[0].players
|
||||||
|
else {
|
||||||
|
const dt = state.updates[0].time - state.updates[1].time
|
||||||
|
return state.updates[1].players.map(player => interpolatePlayer(player, dt))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
socketConnected ({ commit }) {
|
socketConnected ({ commit }) {
|
||||||
commit('SET_CONNECTED')
|
commit('SET_CONNECTED')
|
||||||
|
commit('CLEAR_UPDATE')
|
||||||
},
|
},
|
||||||
login ({ commit }, player) {
|
login ({ commit }, player) {
|
||||||
commit('SET_PLAYER', player)
|
commit('SET_PLAYER', player)
|
||||||
@@ -35,10 +42,11 @@ const actions = {
|
|||||||
commit('SET_SETTINGS', settings)
|
commit('SET_SETTINGS', settings)
|
||||||
},
|
},
|
||||||
update ({ commit }, update) {
|
update ({ commit }, update) {
|
||||||
commit('SET_PLAYERS', update)
|
commit('ADD_UPDATE', update)
|
||||||
},
|
},
|
||||||
dead ({ commit }, player) {
|
dead ({ commit }, player) {
|
||||||
commit('SET_PLAYER', player)
|
commit('SET_PLAYER', player)
|
||||||
|
commit('CLEAR_UPDATE')
|
||||||
},
|
},
|
||||||
error ({ commit }, error) {
|
error ({ commit }, error) {
|
||||||
alert('Error: ' + error)
|
alert('Error: ' + error)
|
||||||
@@ -60,7 +68,21 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_CONNECTED (state) {
|
SET_CONNECTED (state) {
|
||||||
state.socketConnected = !state.socketConnected
|
state.socketConnected = !state.socketConnected
|
||||||
|
},
|
||||||
|
ADD_UPDATE (state, update) {
|
||||||
|
if (state.updates.length > 2) {
|
||||||
|
state.updates.shift()
|
||||||
}
|
}
|
||||||
|
update.time = update.time.epochSecond
|
||||||
|
state.updates.push(update)
|
||||||
|
},
|
||||||
|
CLEAR_UPDATE (state) {
|
||||||
|
state.updates = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function interpolatePlayer (player, dt) {
|
||||||
|
return player
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function createSocketPlugin () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connection.onmessage = function (message) {
|
connection.onmessage = function (message) {
|
||||||
console.log('[WS] message', message.data)
|
// console.log('[WS] message', message.data)
|
||||||
|
|
||||||
var data = JSON.parse(message.data)
|
var data = JSON.parse(message.data)
|
||||||
|
|
||||||
@@ -43,6 +43,6 @@ export default function createSocketPlugin () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function send (message) {
|
export function send (message) {
|
||||||
console.log('[WS] send', message)
|
// console.log('[WS] send', message)
|
||||||
connection.send(JSON.stringify(message))
|
connection.send(JSON.stringify(message))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package gltronic.tronio.business;
|
package gltronic.tronio.business;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
import gltronic.tronio.model.Game;
|
import gltronic.tronio.model.Game;
|
||||||
|
import gltronic.tronio.model.GameUpdate;
|
||||||
import gltronic.tronio.model.Player;
|
import gltronic.tronio.model.Player;
|
||||||
import gltronic.tronio.model.Wall;
|
import gltronic.tronio.model.Wall;
|
||||||
|
|
||||||
@@ -54,8 +57,12 @@ public class GameManager implements IGameManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Scheduled(fixedDelay = 1000 / 60)
|
@Scheduled(fixedDelay = 1000 / 120)
|
||||||
public void step() throws InterruptedException, IOException {
|
public void step() throws InterruptedException, IOException {
|
||||||
|
Instant currentTime = Instant.now();
|
||||||
|
Duration durationSinceLastUpdate = Duration.between(game.getLastUpdate(), currentTime);
|
||||||
|
game.setLastUpdate(currentTime);
|
||||||
|
|
||||||
// CHECK OUT OF BORDERS & COLISIONS
|
// CHECK OUT OF BORDERS & COLISIONS
|
||||||
game.getPlayers().forEach((id, player) -> {
|
game.getPlayers().forEach((id, player) -> {
|
||||||
// OUT OF BORDERS
|
// OUT OF BORDERS
|
||||||
@@ -92,6 +99,10 @@ public class GameManager implements IGameManager {
|
|||||||
|
|
||||||
// ADD WALLS & MOVE PLAYER
|
// ADD WALLS & MOVE PLAYER
|
||||||
game.getPlayers().forEach((id, player) -> {
|
game.getPlayers().forEach((id, player) -> {
|
||||||
|
// On cherche le nombre de pas pour atteindre les 60 up/s
|
||||||
|
long tickToSimulate = ( durationSinceLastUpdate.toMillis() * 120 ) / 1000;
|
||||||
|
|
||||||
|
for (long i = 0; i <= tickToSimulate; i++) {
|
||||||
// WALL
|
// WALL
|
||||||
player.setLastWall(player.getLastWall() + 1);
|
player.setLastWall(player.getLastWall() + 1);
|
||||||
if (player.getLastWall() > game.getSettings().getWallUpdate()) {
|
if (player.getLastWall() > game.getSettings().getWallUpdate()) {
|
||||||
@@ -102,11 +113,15 @@ public class GameManager implements IGameManager {
|
|||||||
// MOVE
|
// MOVE
|
||||||
player.setX(player.getX() + game.getSettings().getPlayerSpeed() * Math.cos(player.getAngle()));
|
player.setX(player.getX() + game.getSettings().getPlayerSpeed() * Math.cos(player.getAngle()));
|
||||||
player.setY(player.getY() + game.getSettings().getPlayerSpeed() * Math.sin(player.getAngle()));
|
player.setY(player.getY() + game.getSettings().getPlayerSpeed() * Math.sin(player.getAngle()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Broadcast une fois sur deux
|
// Broadcast une fois sur deux
|
||||||
if (game.isUpdateNeeded()) {
|
if (game.isUpdateNeeded()) {
|
||||||
SocketUtils.broadcast(game, "gameUpdate", new ObjectMapper().writeValueAsString(game.getPlayers().values()));
|
GameUpdate update = new GameUpdate();
|
||||||
|
update.setTime(game.getLastUpdate());
|
||||||
|
update.setPlayers(game.getPlayers().values());
|
||||||
|
SocketUtils.broadcast(game, "gameUpdate", new ObjectMapper().writeValueAsString(update));
|
||||||
game.setUpdateNeeded(false);
|
game.setUpdateNeeded(false);
|
||||||
} else game.setUpdateNeeded(true);
|
} else game.setUpdateNeeded(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package gltronic.tronio.model;
|
package gltronic.tronio.model;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -17,18 +18,13 @@ public class Game {
|
|||||||
private Map<String, WebSocketSession> sessions;
|
private Map<String, WebSocketSession> sessions;
|
||||||
private GameSettings settings;
|
private GameSettings settings;
|
||||||
private boolean updateNeeded;
|
private boolean updateNeeded;
|
||||||
|
private Instant lastUpdate;
|
||||||
|
|
||||||
public Game() {
|
public Game() {
|
||||||
this.updateNeeded = false;
|
this.updateNeeded = false;
|
||||||
|
this.lastUpdate = Instant.now();
|
||||||
this.players = new HashMap<>();
|
this.players = new HashMap<>();
|
||||||
this.sessions = new HashMap<>();
|
this.sessions = new HashMap<>();
|
||||||
this.settings = new GameSettings();
|
this.settings = new GameSettings();
|
||||||
|
|
||||||
this.settings.setArenaSize(1000);
|
|
||||||
this.settings.setPlayerSize(10);
|
|
||||||
this.settings.setPlayerSpeed(2);
|
|
||||||
this.settings.setPlayerTurnSpeed(10);
|
|
||||||
this.settings.setWallSize(8);
|
|
||||||
this.settings.setWallUpdate(5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
package gltronic.tronio.model;
|
package gltronic.tronio.model;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
|
||||||
public class GameSettings {
|
public class GameSettings {
|
||||||
private double playerSize;
|
private double playerSize;
|
||||||
private double playerSpeed;
|
private double playerSpeed;
|
||||||
@@ -14,4 +12,13 @@ public class GameSettings {
|
|||||||
private double wallSize;
|
private double wallSize;
|
||||||
private double wallUpdate;
|
private double wallUpdate;
|
||||||
private double arenaSize;
|
private double arenaSize;
|
||||||
|
|
||||||
|
public GameSettings () {
|
||||||
|
this.arenaSize = 1000;
|
||||||
|
this.playerSize = 10;
|
||||||
|
this.playerSpeed = 2;
|
||||||
|
this.playerTurnSpeed = 10;
|
||||||
|
this.wallSize = 8;
|
||||||
|
this.wallUpdate = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
17
server/src/main/java/gltronic/tronio/model/GameUpdate.java
Normal file
17
server/src/main/java/gltronic/tronio/model/GameUpdate.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package gltronic.tronio.model;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Component
|
||||||
|
public class GameUpdate {
|
||||||
|
private Collection<Player> players;
|
||||||
|
private Instant time;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
server/target/classes/gltronic/tronio/model/GameUpdate.class
Normal file
BIN
server/target/classes/gltronic/tronio/model/GameUpdate.class
Normal file
Binary file not shown.
Reference in New Issue
Block a user