forked from trent_larson/crowd-funder-for-time-pwa
in stats-world, fix the location computations to be based on Give attributes
This commit is contained in:
@@ -15,12 +15,13 @@ import { createRenderer } from "./systems/renderer.js";
|
||||
|
||||
const COLOR1 = "#dddddd";
|
||||
const COLOR2 = "#0055aa";
|
||||
const PLATFORM_BORDER = 10;
|
||||
const PLATFORM_EDGE_FOR_UNKNOWNS = 10;
|
||||
const PLATFORM_SIZE = 100; // note that the loadLandmarks calculations may still assume 100
|
||||
|
||||
class World {
|
||||
constructor(container, vue) {
|
||||
this.PLATFORM_BORDER = 5;
|
||||
this.PLATFORM_EDGE_FOR_UNKNOWNS = 10;
|
||||
this.PLATFORM_SIZE = 100; // note that the loadLandmarks calculations may still assume 100
|
||||
|
||||
this.update = this.update.bind(this);
|
||||
|
||||
// Instances of camera, scene, and renderer
|
||||
@@ -49,9 +50,11 @@ class World {
|
||||
// Terrain Instance
|
||||
const terrain = createTerrain({
|
||||
color: COLOR1,
|
||||
height: PLATFORM_SIZE + PLATFORM_BORDER * 2,
|
||||
height: this.PLATFORM_SIZE + this.PLATFORM_BORDER * 2,
|
||||
width:
|
||||
PLATFORM_SIZE + PLATFORM_BORDER * 2 + PLATFORM_EDGE_FOR_UNKNOWNS * 2,
|
||||
this.PLATFORM_SIZE +
|
||||
this.PLATFORM_BORDER * 2 +
|
||||
this.PLATFORM_EDGE_FOR_UNKNOWNS * 2,
|
||||
});
|
||||
|
||||
this.loop.updatables.push(controls);
|
||||
|
||||
@@ -1,21 +1,39 @@
|
||||
import axios from "axios";
|
||||
import * as R from "ramda";
|
||||
import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader";
|
||||
import * as SkeletonUtils from "three/addons/utils/SkeletonUtils";
|
||||
import * as TWEEN from "@tweenjs/tween.js";
|
||||
import { AppString } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { accessToken } from "@/libs/crypto";
|
||||
|
||||
const ANIMATION_DURATION_SECS = 10;
|
||||
const BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||||
const ENDORSER_ENTITY_PREFIX = "https://endorser.ch/entity/";
|
||||
|
||||
export async function loadLandmarks(vue, world, scene, loop) {
|
||||
const endorserApiServer = AppString.DEFAULT_ENDORSER_API_SERVER;
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const activeDid = settings?.activeDid || "";
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
const account = R.find((acc) => acc.did === activeDid, accounts);
|
||||
const identity = JSON.parse(account?.identity || "undefined");
|
||||
const token = await accessToken(identity);
|
||||
|
||||
const url =
|
||||
endorserApiServer + "/api/v2/report/claims?claimType=GiveAction";
|
||||
const headers = { "Content-Type": "application/json" };
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer " + token,
|
||||
};
|
||||
const resp = await axios.get(url, { headers: headers });
|
||||
if (resp.status === 200) {
|
||||
console.log("resp.data.data", resp.data.data);
|
||||
const minDate = resp.data.data[resp.data.data.length - 1].issuedAt;
|
||||
const maxDate = resp.data.data[0].issuedAt;
|
||||
const minTimeMillis = new Date(minDate).getTime();
|
||||
@@ -33,24 +51,27 @@ export async function loadLandmarks(vue, world, scene, loop) {
|
||||
//const modelLoc = "/models/coreopsis-flower.glb", // 3 flowers
|
||||
// modScale = 2;
|
||||
//const modelLoc = "/models/a_bush/scene.gltf", // purple leaves
|
||||
// modScale = 15,
|
||||
// modScale = 15;
|
||||
|
||||
// calculate positions for each claim, especially because some are random
|
||||
const locations = resp.data.data.map((claim) =>
|
||||
locForGive(claim, world.PLATFORM_SIZE, world.PLATFORM_EDGE_FOR_UNKNOWNS)
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const parentWorld = world;
|
||||
loader.load(
|
||||
modelLoc,
|
||||
function (gltf) {
|
||||
gltf.scene.scale.set(0, 0, 0);
|
||||
for (const claim of resp.data.data) {
|
||||
for (let i = 0; i < resp.data.data.length; i++) {
|
||||
// claim is a GiveServerRecord (see endorserServer.ts)
|
||||
const claim = resp.data.data[i];
|
||||
const newPlant = SkeletonUtils.clone(gltf.scene);
|
||||
const randomness = claim.id.substring(10);
|
||||
const x =
|
||||
(100 * BASE32.indexOf(randomness.substring(0, 1))) / 32 - 50;
|
||||
const z =
|
||||
(100 * BASE32.indexOf(randomness.substring(8, 9))) / 32 - 50;
|
||||
newPlant.position.set(x, 0, z);
|
||||
|
||||
parentWorld.scene.add(newPlant);
|
||||
const loc = locations[i];
|
||||
newPlant.position.set(loc.x, 0, loc.z);
|
||||
|
||||
world.scene.add(newPlant);
|
||||
const timeDelayMillis =
|
||||
fakeRealRatio *
|
||||
(new Date(claim.issuedAt).getTime() - minTimeMillis);
|
||||
@@ -58,7 +79,7 @@ export async function loadLandmarks(vue, world, scene, loop) {
|
||||
.delay(timeDelayMillis)
|
||||
.to({ x: modScale, y: modScale, z: modScale }, 5000)
|
||||
.start();
|
||||
parentWorld.bushes = [...parentWorld.bushes, newPlant];
|
||||
world.bushes = [...world.bushes, newPlant];
|
||||
}
|
||||
},
|
||||
undefined,
|
||||
@@ -68,16 +89,14 @@ export async function loadLandmarks(vue, world, scene, loop) {
|
||||
);
|
||||
|
||||
// calculate when lights shine on appearing claim area
|
||||
for (const claim of resp.data.data) {
|
||||
for (let i = 0; i < resp.data.data.length; i++) {
|
||||
// claim is a GiveServerRecord (see endorserServer.ts)
|
||||
const claim = resp.data.data[i];
|
||||
|
||||
// compute location for this claim
|
||||
const randomness = claim.id.substring(10);
|
||||
const x = (100 * BASE32.indexOf(randomness.substring(0, 1))) / 32 - 50;
|
||||
const z = (100 * BASE32.indexOf(randomness.substring(8, 9))) / 32 - 50;
|
||||
const loc = locations[i];
|
||||
const light = createLight();
|
||||
light.position.set(x, 20, z);
|
||||
light.target.position.set(x, 0, z);
|
||||
light.position.set(loc.x, 20, loc.z);
|
||||
light.target.position.set(loc.x, 0, loc.z);
|
||||
loop.updatables.push(light);
|
||||
scene.add(light);
|
||||
scene.add(light.target);
|
||||
@@ -119,6 +138,86 @@ export async function loadLandmarks(vue, world, scene, loop) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param giveClaim
|
||||
* @returns {x:float, z:float} where -50 <= x & z < 50
|
||||
*/
|
||||
function locForGive(giveClaim, platformWidth, borderWidth) {
|
||||
let loc;
|
||||
if (giveClaim?.claim?.recipient?.identifier) {
|
||||
// this is directly to a person
|
||||
loc = locForEthrDid(giveClaim.claim.recipient.identifier);
|
||||
loc = { x: loc.x - platformWidth / 2, z: loc.z - platformWidth / 2 };
|
||||
} else if (giveClaim?.object?.isPartOf?.identifier) {
|
||||
// this is probably to a project
|
||||
const objId = giveClaim.object.isPartOf.identifier;
|
||||
if (objId.startsWith(ENDORSER_ENTITY_PREFIX)) {
|
||||
loc = locForUlid(objId.substring(ENDORSER_ENTITY_PREFIX.length));
|
||||
loc = { x: loc.x - platformWidth / 2, z: loc.z - platformWidth / 2 };
|
||||
}
|
||||
}
|
||||
if (!loc) {
|
||||
// it must be outside our known addresses so let's put it somewhere random
|
||||
const leftSide = Math.random() < 0.5;
|
||||
loc = {
|
||||
x: leftSide
|
||||
? -platformWidth / 2 - borderWidth / 2
|
||||
: platformWidth / 2 + borderWidth / 2,
|
||||
z: Math.random() * platformWidth - platformWidth / 2,
|
||||
};
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a deterministic x & z location based on the randomness in a ULID.
|
||||
*
|
||||
* We'll use the first 20 bits for the x coordinate and next 20 for the z.
|
||||
* That's a bit over a trillion locations... should be enough for pretty
|
||||
* unique locations for this fun kind of application within a network
|
||||
* -- though they're not guaranteed unique without the full ID.
|
||||
* (We're leaving 40 bits for other properties.)
|
||||
*
|
||||
* @param ulid
|
||||
* @returns {x: float, z: float} where 0 <= x & z < 100
|
||||
*/
|
||||
function locForUlid(ulid) {
|
||||
// The random parts of a ULID come after the first 10 characters.
|
||||
const randomness = ulid.substring(10);
|
||||
|
||||
// That leaves 16 characters of randomness, or 80 bits.
|
||||
|
||||
// We're currently only using 32 possible x and z values
|
||||
// because the display is pretty low-fidelity at this point.
|
||||
|
||||
// Similar code is below.
|
||||
const x = (100 * BASE32.indexOf(randomness.substring(0, 1))) / 32;
|
||||
const z = (100 * BASE32.indexOf(randomness.substring(4, 5))) / 32;
|
||||
return { x, z };
|
||||
}
|
||||
|
||||
/**
|
||||
* See locForUlid
|
||||
* @param did
|
||||
* @returns {x: float, z: float} where 0 <= x & z < 100
|
||||
*/
|
||||
function locForEthrDid(did) {
|
||||
// "did:ethr:0x..."
|
||||
if (did.length < 51) {
|
||||
return { x: 0, z: 0 };
|
||||
} else {
|
||||
const randomness = did.substring(11);
|
||||
// We'll take the first 4 bits for 16 possible x & z values.
|
||||
const xOff = parseInt(Number("0x" + randomness.substring(0, 1)), 10);
|
||||
const x = (xOff * 100) / 16;
|
||||
// ... and since we're reserving 20 bits total for x, start with character 5.
|
||||
const zOff = parseInt(Number("0x" + randomness.substring(5, 6)), 10);
|
||||
const z = (zOff * 100) / 16;
|
||||
return { x, z };
|
||||
}
|
||||
}
|
||||
|
||||
function createLight() {
|
||||
const light = new THREE.SpotLight(0xffffff, 0, 0, Math.PI / 8, 0.5, 0);
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
|
||||
Reference in New Issue
Block a user