This commit is contained in:
@@ -112,7 +112,8 @@ class AccessManager {
|
||||
lastName: dbUser.lastName,
|
||||
displayName: dbUser.displayName,
|
||||
profilePicture: dbUser.profilePicture,
|
||||
status: dbUser.status
|
||||
status: dbUser.status,
|
||||
gameData: dbUser.gameData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class GamesManager{
|
||||
this.list = async function(query){
|
||||
return await db.list(collection, {
|
||||
query,
|
||||
project: { name:1, description:1, id:1, thumb: 1, group: 1, order: 1}
|
||||
project: { name:1, description:1, id:1, thumb: 1, group: 1, order: 1, activationTriggers: 1}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,21 @@ class UserManager {
|
||||
await db.update(collection, { '_id': db.ObjectId(user._id) }, user);
|
||||
}
|
||||
|
||||
this.addGameData = async function(ctx, data){
|
||||
if (ctx.user?._id){
|
||||
let user = await db.get(collection, { '_id': db.ObjectId(ctx.user._id) });
|
||||
let gameData = (user.gameData || []).filter(gd=>gd.id != data.id);
|
||||
gameData.push(data);
|
||||
ctx.user.gameData = user.gameData = gameData;
|
||||
await db.update(collection, { '_id': db.ObjectId(user._id) }, user);
|
||||
//ctx.user.gameData = gameData;
|
||||
}else{
|
||||
let gameData = (ctx.session.gameData || []).filter(gd=>gd.id != data.id);
|
||||
gameData.push(data);
|
||||
ctx.session.gameData = gameData
|
||||
}
|
||||
}
|
||||
|
||||
this.assignSafeUserData = function (ctx, userObject, newData, isAdmin) {
|
||||
['displayName', 'firstName', 'lastName', ...(isAdmin ? ['roles', 'groups', 'email', 'status'] : [])].forEach(e => {
|
||||
userObject[e] = newData[e];
|
||||
|
||||
@@ -167,6 +167,15 @@ class UsersController {
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/gameData', (req, res) => {
|
||||
res.json(req.user?.gameData || req.session.gameData || []);
|
||||
})
|
||||
|
||||
router.put('/gameData', async (req, res) => {
|
||||
await user.addGameData(req, req.body);
|
||||
res.json(req.user?.gameData || req.session.gameData || []);
|
||||
})
|
||||
|
||||
app.webServer.xapp.use(this.route, router);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ export default {
|
||||
mode: 'GamePlay'
|
||||
});
|
||||
manager = await new GameManager(engine, this.id);
|
||||
manager.addEventListener('the-end', _=>{
|
||||
manager.addEventListener('the-end', async e =>{
|
||||
await this.$api.user.addGameData({ id: this.id, score: e.score });
|
||||
this.$router.push('/');
|
||||
})
|
||||
window.addEventListener('resize', this.resize);
|
||||
|
||||
@@ -116,7 +116,6 @@ class PuzzleGame1 extends EventManager {
|
||||
s: 'PG2'
|
||||
});
|
||||
});
|
||||
//engine.dashboard.addPoints(10);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -160,7 +160,6 @@ class PuzzleGame2 extends EventManager {
|
||||
s: 'PG2'
|
||||
});
|
||||
});
|
||||
//engine.dashboard.addPoints(10);
|
||||
}
|
||||
};
|
||||
engine.addEventListener('beforeRender', this.update)
|
||||
|
||||
@@ -117,7 +117,6 @@ var PuzzleGame4 = function(context, gltf, w, h){
|
||||
})
|
||||
})
|
||||
this.dispatchEvent({type:'finish'})
|
||||
//context.dashboard.addPoints(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,12 @@ const api = {
|
||||
},
|
||||
async update(data){
|
||||
return await $ax.post('/user/update', data);
|
||||
},
|
||||
async addGameData(data){
|
||||
return await $ax.put('/user/gameData', data);
|
||||
},
|
||||
async getGameData(){
|
||||
return await $ax.get('/user/gameData');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-2
@@ -59,7 +59,7 @@ class GameManager extends EventManager{
|
||||
}
|
||||
let expectToFinish = 0, finished = 0, iobjs = [];
|
||||
if (scene.data.items){
|
||||
let loaded = 0;
|
||||
let loaded = 0, maxPoints = 0;
|
||||
for (let i of scene.data.items) {
|
||||
//this.debug('Loading', i.data.id);
|
||||
if (engine.opts.mode != 'GameDesigner'){
|
||||
@@ -75,6 +75,7 @@ class GameManager extends EventManager{
|
||||
}
|
||||
this.setObjectAttributes(sceneObjects, i.data, io.object, io.source, 1);
|
||||
engine.activeObjects.add(io.object);
|
||||
maxPoints += io.maxPoints;
|
||||
if (engine.opts.mode != 'GameDesigner'){
|
||||
if (i.data.$go?.type == 'player3d'){
|
||||
let hero = new Hero(engine, io);
|
||||
@@ -115,7 +116,15 @@ class GameManager extends EventManager{
|
||||
//this.scenesList = [this.scenes.find(s=>s.data.id == e.scene)]
|
||||
//switch to next scene:
|
||||
if (e.scene == '__end__'){
|
||||
this.dispatchEvent({ type: 'the-end' });
|
||||
let score = {
|
||||
value: engine.dashboard.points,
|
||||
max: maxPoints
|
||||
}
|
||||
this.dispatchEvent({
|
||||
type: 'the-end',
|
||||
score
|
||||
});
|
||||
engine.tm?.completeGame(gameData.id, score);
|
||||
}else{
|
||||
this.loadScene(e.scene);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ class Telemetry {
|
||||
this.game = game;
|
||||
this.gameStart = Math.round(performance.now()/1000);
|
||||
}
|
||||
completeGame(game, score){
|
||||
this.#af('game:complete', game, { mode: this.mode, game, score });
|
||||
}
|
||||
setScene(scene){
|
||||
if (this.scene == scene) { return; }
|
||||
if (this.scene){
|
||||
|
||||
+5
-2
@@ -3,7 +3,7 @@
|
||||
<h1 class="text-h5 my-2" style="border-bottom:1px solid grey">{{ g }}</h1>
|
||||
<v-row>
|
||||
<v-col v-for="(v, i) in items.filter(t=>t.group == g).sort((a, b)=>(a.order||0) - (b.order||0) )" :key="i" cols="12" xs="6" sm="6" md="4" xl="4">
|
||||
<v-card :to="`/playground/game/${v.id}`" class="hover-effect">
|
||||
<v-card :to="`/playground/game/${v.id}`" :class="'hover-effect' + (v.locked ? ' locked' : '')">
|
||||
<v-img :src="`/asset/thumb/${v.thumb}.webp`" cover content-class="d-flex flex-column justify-end" gradient="to bottom, rgba(0,0,0,0), rgba(0,0,0,.5)">
|
||||
<v-card-title class="text-white text-h6" v-text="v.name"></v-card-title>
|
||||
<div class="text-white text-caption mx-4" v-text="v.description"></div>
|
||||
@@ -19,16 +19,19 @@ export default {
|
||||
data(){
|
||||
return {
|
||||
items: [],
|
||||
groups: []
|
||||
groups: [],
|
||||
gameData: []
|
||||
}
|
||||
},
|
||||
|
||||
async created(){
|
||||
this.gameData = (await this.$api.user.getGameData()).data
|
||||
this.items = (await this.$api.game.search()).data.data;
|
||||
this.items.forEach(i=>{
|
||||
if (this.groups.indexOf(i.group) == -1){
|
||||
this.groups.push(i.group);
|
||||
}
|
||||
i.locked = (i.activationTriggers||[]).filter(at=>!this.gameData.find(gd=>gd.id == at)).length
|
||||
})
|
||||
this.groups.sort();
|
||||
},
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
<v-textarea :label="l.description" v-model="object.description"></v-textarea>
|
||||
<v-text-field :label="l.group" v-model="object.group"></v-text-field>
|
||||
<v-number-input density="compact" :label="l.order" v-model="object.order"></v-number-input>
|
||||
<v-select density="compact" :label="l.completionElements" v-model="object.activationTriggers"
|
||||
:items="games.filter(v=>v.id != id).map(v=>({title: v.name, value: v.id}))" multiple >
|
||||
</v-select>
|
||||
<v-select :label="l.scenario" :items="scenarios" :disabled="this.id != 'add'" v-model="object.scenario" item-title="name" item-value="id"></v-select>
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
@@ -39,7 +42,8 @@ export default {
|
||||
},
|
||||
loading: false,
|
||||
panel: [],
|
||||
scenarios: []
|
||||
scenarios: [],
|
||||
games: []
|
||||
}
|
||||
},
|
||||
async mounted(){
|
||||
@@ -47,6 +51,7 @@ export default {
|
||||
this.object = (await this.$api.game.load(this.id)).data;
|
||||
}
|
||||
this.scenarios = (await this.$api.scenario.search()).data.data;
|
||||
this.games = (await this.$api.game.search()).data.data;
|
||||
},
|
||||
watch:{
|
||||
'object.scenario'(v){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-container max-width="1400">
|
||||
<GamePlay :id="$route.params?.id"></GamePlay>
|
||||
<GamePlay :id="parseInt($route.params?.id)"></GamePlay>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -84,6 +84,24 @@ video{
|
||||
}
|
||||
}
|
||||
|
||||
.locked {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
position: relative;
|
||||
&::after{
|
||||
content:"\F033E";
|
||||
text-align: center;
|
||||
font-family: "Material Design Icons";
|
||||
font-size: 111px;
|
||||
opacity: 0.5;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left:0;
|
||||
top:0;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-container{
|
||||
svg{
|
||||
image{
|
||||
|
||||
Reference in New Issue
Block a user