what the FUCK is happening
This commit is contained in:
parent
ea2c22bb98
commit
63092c66d8
1 changed files with 337 additions and 0 deletions
337
if-it-dies-in-game-it-dies-in-real-life/index.html
Normal file
337
if-it-dies-in-game-it-dies-in-real-life/index.html
Normal file
|
@ -0,0 +1,337 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
:root {
|
||||
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||
background-color: black;
|
||||
color: #efefef;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#dot,
|
||||
#safetyDot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: red;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main>
|
||||
<section>
|
||||
<div>
|
||||
<label for="safety">SAFETY LOCK</label>
|
||||
<input type="checkbox" name="safety" id="safety" value="true" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="arm">ARM DOLL CONTROL</label>
|
||||
<input type="checkbox" name="arm" id="arm" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="intensity">Intensity</label><br />
|
||||
<input id="intensity" type="range" min="1" max="5" value="3" />
|
||||
<button id="pair">Pair</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="targets">Targets</label><br />
|
||||
<textarea id="targets" width="50">
|
||||
DollTR
|
||||
DollNC
|
||||
DollVS
|
||||
WitchOfTheHighlands
|
||||
41666
|
||||
xenogender
|
||||
</textarea
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label for="targets">Attackers</label><br />
|
||||
<textarea id="attackers">
|
||||
Lyyti
|
||||
LyytiTR
|
||||
LyytiNC
|
||||
</textarea
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" id="connect" value="Connect" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="dot"></div>
|
||||
<span id="dotText">Not Armed</span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="safetyDot"></div>
|
||||
<span id="safetyDotText">Safety ON (commands will not be sent)</span>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2>log</h2>
|
||||
<pre id="log"></pre>
|
||||
</section>
|
||||
</main>
|
||||
<script defer async>
|
||||
window.__ARMED__ = false;
|
||||
window.__SAFETY__ = true;
|
||||
window.__CONNECTED__ = false;
|
||||
|
||||
const COLLAR_BT_NAME = "PetSafe Smart Dog Trainer";
|
||||
const COLLAR_COMMAND_SERVICE = "0bd51666-e7cb-469b-8e4d-2742f1ba77cc";
|
||||
const COLLAR_COMMAND_CHARACTERISTIC = "e7add780-b042-4876-aae1-112855353cc1";
|
||||
const COLLAR_AUTH_CHARACTERISTIC = "0e7ad781-b043-4877-aae2-112855353cc2";
|
||||
const COLLAR_TONE_COMMAND = [0x55, 0x36, 0x31, 0x31, 0x31, 0x30];
|
||||
const COLLAR_VIBRATE_COMMAND = [0x55, 0x36, 0x31, 0x33, 0x33, 0x30];
|
||||
// Last byte is command strength (0-15) + 0x48. We set it to 0 here.
|
||||
const COLLAR_STATIC_COMMAND = [0x55, 0x36, 0x31, 0x32, 0x33, 0x30];
|
||||
// Last four bytes are the ASCII values of the PIN digits
|
||||
const COLLAR_AUTH_COMMAND = [0x55, 0x37, 0x37, 0x30, 0x30, 0x30, 0x30];
|
||||
|
||||
class PetsafeSmartDogTrainingCollar {
|
||||
constructor() {
|
||||
this.device = null;
|
||||
this.service = null;
|
||||
this.tx = null;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
console.log("Starting connect");
|
||||
|
||||
if (!navigator.bluetooth) {
|
||||
addLogMessage("No WebBluetooth support; bailing.");
|
||||
throw new Error("No WebBluetooth; bailing.");
|
||||
}
|
||||
|
||||
this.device = await navigator.bluetooth.requestDevice({
|
||||
filters: [
|
||||
{
|
||||
name: COLLAR_BT_NAME,
|
||||
},
|
||||
],
|
||||
optionalServices: [COLLAR_COMMAND_SERVICE],
|
||||
});
|
||||
let server = await this.device.gatt.connect();
|
||||
this.service = await server.getPrimaryService(COLLAR_COMMAND_SERVICE);
|
||||
this.tx = await this.service.getCharacteristic(
|
||||
COLLAR_COMMAND_CHARACTERISTIC
|
||||
);
|
||||
this.auth = await this.service.getCharacteristic(
|
||||
COLLAR_AUTH_CHARACTERISTIC
|
||||
);
|
||||
console.log("Connected");
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
await this.device.gatt.disconnect();
|
||||
}
|
||||
async authorize(d1, d2, d3, d4) {
|
||||
console.log("Authenticating with ", d1, d2, d3, d4);
|
||||
let r = new Uint8Array(COLLAR_AUTH_COMMAND);
|
||||
r[3] += d1;
|
||||
r[4] += d2;
|
||||
r[5] += d3;
|
||||
r[6] += d4;
|
||||
console.log(r);
|
||||
this.auth.writeValue(r);
|
||||
}
|
||||
async runTone() {
|
||||
console.log("Running tone");
|
||||
addLogMessage("[TONE]");
|
||||
this.tx.writeValue(new Uint8Array(COLLAR_TONE_COMMAND));
|
||||
}
|
||||
|
||||
async runVibrate() {
|
||||
console.log("Running vibration");
|
||||
addLogMessage("[VIBRATE]");
|
||||
this.tx.writeValue(new Uint8Array(COLLAR_VIBRATE_COMMAND));
|
||||
}
|
||||
|
||||
async runStatic(power) {
|
||||
if (window.__SAFETY__) {
|
||||
addLogMessage("SAFETY ON; runStatic REJECTED");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Running static");
|
||||
addLogMessage("[SHOCK] Power = " + power);
|
||||
if (power < 0 || power > 15) {
|
||||
throw Error("power not in range 0-15");
|
||||
}
|
||||
let r = new Uint8Array(COLLAR_STATIC_COMMAND);
|
||||
r[5] += power;
|
||||
console.log(r);
|
||||
this.tx.writeValue(r);
|
||||
}
|
||||
}
|
||||
|
||||
const collar = new PetsafeSmartDogTrainingCollar();
|
||||
|
||||
const addLogMessage = (message) => {
|
||||
const logEl = document.querySelector("#log");
|
||||
logEl.innerHTML = `${new Date().toISOString()} :: ${message}\n${
|
||||
logEl.innerHTML
|
||||
}`;
|
||||
};
|
||||
|
||||
const setStatus = (color, text) => {
|
||||
document.querySelector("#dot").style.backgroundColor = color;
|
||||
document.querySelector("#dotText").innerHTML = text;
|
||||
};
|
||||
|
||||
const setSafety = (color, text) => {
|
||||
document.querySelector("#safetyDot").style.backgroundColor = color;
|
||||
document.querySelector("#safetyDotText").innerHTML = text;
|
||||
};
|
||||
|
||||
const connectCollar = async (pin) => {
|
||||
addLogMessage("Connecting to collar...");
|
||||
await collar.connect();
|
||||
addLogMessage("Collar connected; running vibration test.");
|
||||
await collar.runVibrate();
|
||||
};
|
||||
|
||||
const fire = () => {
|
||||
if (window.__SAFETY__ || !window.__ARMED__) {
|
||||
addLogMessage("SAFETY ON or NOT ARMED -- FIRE REJECTED.");
|
||||
return;
|
||||
}
|
||||
|
||||
const intensity = Number(document.querySelector("#intensity").value);
|
||||
|
||||
collar.runStatic(intensity || 0);
|
||||
};
|
||||
|
||||
const resolveCharacters = async (list) => {
|
||||
const url = `https://census.daybreakgames.com/s:saegd/get/ps2/character_name?name.first_lower=${list
|
||||
.map((a) => a.toLowerCase())
|
||||
.join(",")}&c:limit=${list.length}`;
|
||||
|
||||
const req = await fetch(url);
|
||||
const data = await req.json();
|
||||
|
||||
return data.character_name_list.map((a) => a.character_id);
|
||||
};
|
||||
|
||||
const connectToESS = (targets, attackers) => {
|
||||
addLogMessage("Connecting to WSS...");
|
||||
const ws = new WebSocket(
|
||||
"https://push.nanite-systems.net/streaming?environment=ps2&service-id=s:saegd"
|
||||
);
|
||||
|
||||
ws.onopen = () => {
|
||||
setTimeout(() => {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
service: "event",
|
||||
action: "subscribe",
|
||||
characters: targets,
|
||||
eventNames: ["Death"],
|
||||
worlds: ["all"],
|
||||
logicalAndCharactersWithWorlds: true,
|
||||
})
|
||||
);
|
||||
|
||||
addLogMessage(`CONNECTED. Listening to ${targets}`);
|
||||
setStatus("green", "CONNECTED");
|
||||
|
||||
addLogMessage(`will match on ${attackers}`);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
ws.onerror = ws.onclose = (a) => {
|
||||
console.log("ess fail", a);
|
||||
addLogMessage("ESS failed to connect. Reload.");
|
||||
};
|
||||
|
||||
ws.onmessage = (message) => {
|
||||
const { payload } = JSON.parse(message.data);
|
||||
|
||||
if (payload.event_name === "Death") {
|
||||
console.log("Death event", { payload });
|
||||
if (attackers.includes(payload.attacker_character_id)) {
|
||||
addLogMessage(
|
||||
`<b>[TRIGGERED]</b> Death from ${payload.attacker_character_id} to ${payload.character_id}`
|
||||
);
|
||||
|
||||
if (window.__SAFETY__ || !window.__ARMED__) {
|
||||
addLogMessage("SAFETY ON or NOT ARMED -- NO FIRE");
|
||||
return;
|
||||
}
|
||||
|
||||
fire();
|
||||
} else {
|
||||
addLogMessage(
|
||||
`Death event skipped, from ${payload.attacker_character_id} to ${payload.character_id}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
document.querySelector("#arm").addEventListener("change", (event) => {
|
||||
window.__ARMED__ = event.target.checked;
|
||||
|
||||
if (event.target.checked) {
|
||||
addLogMessage("ARMED");
|
||||
setStatus("yellow", "ARMED");
|
||||
} else {
|
||||
addLogMessage("Disarmed.");
|
||||
setStatus("red", "Not Armed");
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector("#safety").addEventListener("change", (event) => {
|
||||
window.__SAFETY__ = event.target.checked;
|
||||
|
||||
if (event.target.checked) {
|
||||
addLogMessage("Safety is on; shock commands will NOT be sent.");
|
||||
setSafety("red", "Safety ON (commands will not be sent)");
|
||||
} else {
|
||||
addLogMessage("Safety is off. Good luck, dolly.");
|
||||
setSafety("green", "Safety OFF");
|
||||
}
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector("#connect")
|
||||
.addEventListener("click", async (event) => {
|
||||
if (window.__CONNECTED__) {
|
||||
addLogMessage("Connection rejected; already connected.");
|
||||
return;
|
||||
}
|
||||
if (!window.__ARMED__) {
|
||||
addLogMessage("Connection rejected; arm the doll.");
|
||||
return;
|
||||
}
|
||||
|
||||
const targets = document.querySelector("#targets").value.split("\n");
|
||||
const attackers = document.querySelector("#attackers").value.split("\n");
|
||||
|
||||
window.__CONNECTED__ = true;
|
||||
|
||||
setStatus("blue", "CONNECTING...");
|
||||
addLogMessage("Fetching character IDs...");
|
||||
const [targetIDs, attackerIDs] = await Promise.all([
|
||||
resolveCharacters(targets),
|
||||
resolveCharacters(attackers),
|
||||
]);
|
||||
connectToESS(targetIDs, attackerIDs);
|
||||
});
|
||||
|
||||
document.querySelector("#pair").addEventListener("click", () => {
|
||||
// const pin = document.querySelector("#pin").value;
|
||||
connectCollar();
|
||||
});
|
||||
|
||||
document.querySelector("#safety").checked = true;
|
||||
document.querySelector("#arm").checked = false;
|
||||
addLogMessage("Safety is on; shock commands will NOT be sent.");
|
||||
addLogMessage("Ready");
|
||||
</script>
|
Loading…
Add table
Reference in a new issue