Skip to content

Commit

Permalink
# Client updates:
Browse files Browse the repository at this point in the history
* Updated 128x128_star_black_hole.svg and 128x128_star_scannable_binary.svg to be styled using a CSS class so that their styles can be overridden.
* Added 128x128_star_pulsar.svg.
* Added SvgWrapper component to allow SVG files to be rendered directly to the DOM (and thus be affected by CSS classes in the DOM) instead of loading them in their own shadow DOMs.
* Added StarIcon component for displaying star icons in the UI consistently.
* Added SortInfo class.
* Added GridHelper class.
* Updated tables:
    - Consolidated sorting functionality and added the capability for tables to be sorted by multiple values, eg sort by specialist name and then by star name.
    - Added capability to be able to sort by more columns, eg specialists and players.
    - Fixed some tables sorting by ship count when clicking on the Name header instead of the Name.
    - Added various tooltips.
    - Tables now respond to time machine ot tick changes.
    - Split resources are now shown as separate, sortable columns.
    - Infrastructure values now have proper columns.
    - Added Warp Gate column to Stars table.
    - Fixed player icon shape always being a circle on some tables.
    - Updated Technology table to show colours indicating whether the current player's technology is the best or worst, matching how it behaves on the player modal Technology section.
    - Fixed Empires table not having colours for Economy, Industry and Science values.
    - Added Star Types table.
* Updated MainMenu component to also load player roles when mounted.
* Updated reloadGameCheck() in Game component:
    - to emit a new onGameTick event when the game ticks.
    - to play a sound and show a toast message when a new tick occurs, even if the player is viewing a historic tick.
* Updated TickSelector component:
    - to move to the latest tick when a new tick occurs, if the player was previously viewing the latest tick.
    - to have a minimum tick matching the minimum tick stored in the time machine (ie if it doesn't exist in the time machine, it won't be selectable).
* Renamed calculateTicksToNextShip() method in gameHelper to calculateTicksToBonusShip(), and updated its functionality to calculate the number of ticks to the bonus ship (which will just be the next ship if the star is producing less than 1 ship per tick).
* Updated StarDetail component to show ticks to bonus ship instead of next ship if the star is producing more than 1 ship per tick.
* Fixed client-side only issue where science infrastructure upgrades did not reflecting whether or not a Research Station existed until the page was refreshed.

# Server updates:
* Added getHistoryMinimumTick() method to HistoryService.
* Updated Repository class:
    - Added types.
    - Fixed returning awaited promise results from Promise<void> methods.
    - Added missing await to countAll() method.
* Updated getUserCount() method in UserService to fix missing await in async method.
* Added timeMachineMinimumTick property to Game interface.
* Added ownerByPlayer property to MapObject interface.
* Updated GameGalaxyService:
    - Updated getGalaxy() method to set new timeMachineMinimumTick property.
    - Updated _setStarInfoBasic(), _setStarInfoDetailed() and _setCarrierInfoDetailed() methods to set new ownerByPlayer property.
  • Loading branch information
Metritutus committed Sep 25, 2024
1 parent 15ec3a9 commit 9da1eb0
Show file tree
Hide file tree
Showing 49 changed files with 1,247 additions and 830 deletions.
9 changes: 9 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"voronoi": "^1.0.0",
"vue": "^2.6.12",
"vue-chartjs": "^3.5.1",
"vue-fragment": "^1.6.0",
"vue-recaptcha": "^1.3.0",
"vue-router": "^3.5.1",
"vue-socket.io": "^3.0.10",
Expand Down
11 changes: 9 additions & 2 deletions client/src/assets/map-objects/128x128_star_black_hole.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions client/src/assets/map-objects/128x128_star_scannable_binary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions client/src/assets/stars/128x128_star_pulsar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion client/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Toasted from 'vue-toasted'
import App from './App.vue'
import router from './router'
import store from './store'

import { Plugin as FragmentPlugin } from 'vue-fragment'
import $ from 'jquery'
import 'pixi.js-legacy'
import 'pixi-viewport'
Expand Down Expand Up @@ -80,6 +80,8 @@ Vue.directive('tooltip', function(el, binding) {
})
})

Vue.use(FragmentPlugin);

new Vue({
router,
store,
Expand Down
40 changes: 40 additions & 0 deletions client/src/services/data/sortInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export default class SortInfo {
propertyPaths;
sortAscending;

constructor(propertyPaths, sortAscending) {
this.propertyPaths = propertyPaths ?? null;
this.sortAscending = sortAscending ?? true;
}

swapSort(propertyPaths) {
// If sorting by a new column, reset the sort.
if (JSON.stringify(this.propertyPaths) !== JSON.stringify(propertyPaths)) {
this.propertyPaths = !Array.isArray(propertyPaths[0]) ? [propertyPaths] : propertyPaths;
this.sortAscending = true
} else {
// Otherwise if we are sorting by the same column, flip the sort direction.
this.sortAscending = !this.sortAscending
}
}

static fromJSON(jsonSortInfo, defaultSortInfo) {
let parsedSortInfo = null;

try {
parsedSortInfo = jsonSortInfo != undefined ? JSON.parse(jsonSortInfo) : null;
}
catch (e) {
console.warn(`SortInfo.fromJSON failed to parse the following JSON: ${jsonSortInfo}`);
console.warn(e);
}

// Fall back to defaults if we have them!
if (parsedSortInfo?.propertyPaths != null && parsedSortInfo?.sortAscending != null) {
return new SortInfo(parsedSortInfo?.propertyPaths, parsedSortInfo?.sortAscending);
}
else {
return new SortInfo(defaultSortInfo?.propertyPaths, defaultSortInfo?.sortAscending);
}
}
}
11 changes: 6 additions & 5 deletions client/src/services/gameHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,7 @@ class GameHelper {
userPlayer.stats.totalIndustry++
break;
case 'science':
userPlayer.stats.totalScience += game.constants.research.sciencePointMultiplier
userPlayer.stats.totalScience += game.constants.research.sciencePointMultiplier * (star.specialistId === 11 ? 2 : 1); // Research Station
break;
}

Expand Down Expand Up @@ -1256,18 +1256,19 @@ class GameHelper {
return game.galaxy.teams.find(t => t._id === teamId);
}

calculateTicksToNextShip(shipsActual, manufacturing) {
calculateTicksToBonusShip(shipsActual, manufacturing) {
if (manufacturing <= 0) {
return null
}

const next = Math.floor(shipsActual + 1);
let current = shipsActual;
const next = 1;
const partialManufacturing = manufacturing - Math.floor(manufacturing);
let current = shipsActual - Math.floor(shipsActual);
let count = 0;

while (current < next) {
count++;
current += manufacturing;
current += partialManufacturing;
}

return count;
Expand Down
61 changes: 61 additions & 0 deletions client/src/services/gridHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class GridHelper {
getNestedObject(nestedObj, pathArr) {
if (!Array.isArray(pathArr)) {
pathArr = pathArr.split(',')
}

return pathArr.reduce((obj, key) =>
(obj && obj[key] !== undefined) ? obj[key] : null, nestedObj)
}

dynamicSort(data, sortInfo) {
if (sortInfo?.propertyPaths != null) {
data = data.sort((a, b) => this.dynamicCompare(a, b, sortInfo));
}

return data;
}

dynamicCompare(a, b, sortInfo) {
let result = 0;

for (let propertyPath of sortInfo.propertyPaths) {
let bo = this.getNestedObject(b, propertyPath);
let ao = this.getNestedObject(a, propertyPath);

result = this.compare(ao, bo);

if (result !== 0) {
break;
}
}

return sortInfo.sortAscending ? result : -result;
}

compare(a, b) {
if (a === b) {
return 0;
}
// Sort null values after everything else
else if (a === null) {
return 1;
}
else if (b === null) {
return -1;
}
else {

let result = a < b ? -1 : 1;

// Invert booleans - we want true values to come first.
if (typeof a === 'boolean' && typeof b === 'boolean') {
result = -result;
}

return result;
}
}
}

export default new GridHelper()
12 changes: 9 additions & 3 deletions client/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,16 @@ export default new Vuex.Store({
},

gameStarBulkUpgraded (state, data) {
let player = GameHelper.getUserPlayer(state.game)
let player = GameHelper.getUserPlayer(state.game);

let newScience = 0;

data.stars.forEach(s => {
let star = GameHelper.getStarById(state.game, s.starId)
let star = GameHelper.getStarById(state.game, s.starId);

if (data.infrastructureType === 'science') {
newScience += s.infrastructure * (star.specialistId === 11 ? 2 : 1); // Research Station
}

star.infrastructure[data.infrastructureType] = s.infrastructure

Expand Down Expand Up @@ -307,7 +313,7 @@ export default new Vuex.Store({
player.stats.totalIndustry += data.upgraded
break;
case 'science':
player.stats.totalScience += (data.upgraded * state.game.constants.research.sciencePointMultiplier)
player.stats.totalScience += (newScience * state.game.constants.research.sciencePointMultiplier)
break;
}
},
Expand Down
5 changes: 3 additions & 2 deletions client/src/views/MainMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default {
}
},
mounted () {
this.loadAchievements()
this.loadData()
},
methods: {
async logout () {
Expand All @@ -172,13 +172,14 @@ export default {
router.push({ name: 'home' })
},
async loadAchievements () {
async loadData () {
try {
let response = await userService.getMyUserInfo()
this.user = response.data
this.achievements = response.data.achievements
this.$store.commit('setRoles', response.data.roles)
this.$store.commit('setUserCredits', response.data.credits)
this.$store.commit('setUserIsEstablishedPlayer', response.data.isEstablishedPlayer)
} catch (err) {
Expand Down
53 changes: 53 additions & 0 deletions client/src/views/components/SvgWrapper.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<object type="image/svg+xml" :data="href" v-on:load="onload($event)" />
</template>

<script>
export default {
props: {
href: null
},
methods: {
onload: function (e) {
// Based on information from here: https://stackoverflow.com/questions/22252409/manipulating-external-svg-file-style-properties-with-css/72804140#72804140
// Basically we elevate our SVG out of the shadow DOM to the DOM, so that it can then be affected by our CSS classes!
// Carry over our existing CSS classes to the SVG.
e.target.contentDocument.documentElement.classList.add(...e.target.classList);
// Copy the data- attributes so the CSS classes will work, etc.
for (let attribute of e.target.attributes) {
if (attribute.name.startsWith('data-')) {
e.target.contentDocument.documentElement.setAttribute(attribute.name, attribute.value);
}
}
// Trim the space around the actual icon!
let svgBoundingBox = this.horribleSvgGetBBox(e.target.contentDocument.documentElement);
e.target.contentDocument.documentElement.setAttribute('viewBox', `${svgBoundingBox.x} ${svgBoundingBox.y} ${svgBoundingBox.width} ${svgBoundingBox.height}`);
// Elevate the SVG element at last!
e.target.parentNode.replaceChild(e.target.contentDocument.documentElement, e.target);
},
horribleSvgGetBBox(svg) {
// This abomination is needed because getBBox() returns all zeroes if the SVG isn't currently "visible".
// Based on the answers from here: https://stackoverflow.com/questions/28282295/getbbox-of-svg-when-hidden
let svgClone = svg.cloneNode(true);
let div = document.createElement('div', {});
div.setAttribute('style', 'position: absolute; visibility: hidden; width: 0; height: 0');
div.appendChild(svgClone);
document.body.appendChild(div);
let bbBox = svgClone.getBBox();
document.body.removeChild(div);
return bbBox;
}
}
}
</script>

<style scoped>
</style>
11 changes: 7 additions & 4 deletions client/src/views/game/Game.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import moment from 'moment'
import gameHelper from '../../services/gameHelper'
import authService from '../../services/api/auth'
import ColourOverrideDialog from "./components/player/ColourOverrideDialog.vue";
import eventBus from '../../eventBus'
export default {
components: {
Expand Down Expand Up @@ -394,12 +395,14 @@ export default {
this.$store.commit('setTick', response.data.state.tick)
this.$store.commit('setProductionTick', response.data.state.productionTick)
} else {
await this.reloadGame()
await this.reloadGame();
}
this.$toasted.show(`The game has ticked. Cycle ${response.data.state.productionTick}, Tick ${response.data.state.tick}.`, { type: 'success' })
eventBus.$emit('onGameTick');
this.$toasted.show(`The game has ticked. Cycle ${response.data.state.productionTick}, Tick ${response.data.state.tick}.`, { type: 'success' });
AudioService.download()
}
AudioService.download();
}
}
} catch (e) {
Expand Down
Loading

0 comments on commit 9da1eb0

Please sign in to comment.