Bonus - Fishing Mastery⚓︎
Objective⚓︎
Fishing objective!
Request
Catch twenty different species of fish that live around Geese Islands. When you're done, report your findings to Poinsettia McMittens on the Island of Misfit Toys.
Poinsettia McMittens
Excuse me, but you're interrupting my fishing serenity. Oh, you'd like to know how to become as good at fishing as I am?
Well, first of all, thank you for noticing my flair for fishing. It's not just about looking good beside the lake, you know.
Become the Fish
Perhaps there are some clues about the local aquatic life located in the HTML source code.
Fishing Machine
There are a variety of strategies for automating repetative website tasks. Tools such as AutoKey and AutoIt allow you to programmatically examine elements on the screen and emulate user inputs.
Solution⚓︎
In source code we have found interesting link, which will be required to catch some rare fishes:
<!-- <a href='fishdensityref.html'>[DEV ONLY] Fish Density Reference</a> -->
First we started inspecting source code and console tools.
We can see messages sent bidirectionally to this WebSoscket endpoint: wss://2023.holidayhackchallenge.com/sail?dockSlip=4606a58c-ccff-4bbf-b9c7-66bcba107161.
After inspecing WS communication we can see interesting messages whenever we catch a fish.
e:{"65139":{"uid":65139,"username":"LS1942","x":790.122627300308,"y":1669.9187716418694,"o":1,"vx":0,"vy":0,"config":{"colors":["plaid","black","blue"],"progress":[false,false,false,true,true,true]},"fishCaught":[{"name":"JellyChip CuddleSwimmer","description":"<-- removed -->","hash":"f71ba29843c1d46325da6e8ec821896b"}],"bearing":"spi-coggogglemarina","canFish":true,"ports":["ci-rudolphsrest","imt-squarewheelyard","imt-scaredykiteheights","imt-tarnishedtrove","spi-coggogglemarina","spi-brassbouyport","pi-rainrastercliffs","si-spaceportpoint","staging","fni-theblacklightdistrict","ci-frostysbeach","spi-rustyquay"],"showOthers":true,"keyState":0,"colors":["plaid","black","blue"],"progress":[false,false,false,true,true,true],"fishing":true,"onTheLine":"The Speckled Pizzafin Fizzflyer"}}
We need to make sure to properly decode those json messages and monitor onTheLine value whenever received.
To catch most rare fish (Piscis Cyberneticus Skodo) we used heatmap located here: https://2023.holidayhackchallenge.com/sea/fishdensityref.html. The existing JavaScript script was overridden with a custom version, this piece of code was modified: img src="assets/noise/Piscis Cyberneticus Skodo.png"
const ImageAssets = {
ship: 'assets/ship.png',
rod: 'assets/rod.png',
roddown: 'assets/roddown.png',
bobber: 'assets/bobber.png',
shipclip: 'assets/shipclip.png',
blocks: 'assets/blocks.png',
ocean: 'assets/ocean.png',
detail: 'assets/island_detail.png',
buoy: 'assets/buoy.png',
wave: 'assets/wave.png',
bump: 'assets/bump.png',
minimap: 'assets/minimap.png',
miniboat: 'assets/miniboat.png',
shadow: 'assets/shadow.png',
startflag: 'assets/startflag.png',
finishflag: 'assets/finishflag.png',
arrow: 'assets/arrow.png',
};
This is exact place where we need to hunt for our rare specie. Heat map black colour mean you won't be able to hunt fish so we need to go white spot.
Below we can see JS script for TamperMonkey extension. ChatGPT was used to develop it.
Example prompts:
write websocket script for tampermonkey extension to interact with websockets on url wss://2023.holidayhackchallenge.com/
// ==UserScript==
// @name WebSocket Hook Script with Selective JSON Processing
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Hook into existing WebSocket connections, selectively process JSON messages
// @author Your Name
// @match https://2023.holidayhackchallenge.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
var OriginalWebSocket = window.WebSocket;
var webSockets = [];
var reelSent = false;
var caughtFishList = [];
function searchOnTheLine(obj) {
for (var key in obj) {
if (typeof obj[key] === 'object') {
// If the current value is an object, recursively search it
searchOnTheLine(obj[key]);
} else if (key === 'onTheLine') {
// If the key is 'onTheLine', check its value
if (obj[key] !== false) {
console.log(obj[key]);
// If the value is not false, send a "cast" message
sendMessage('reel');
reelSent = true;
// Set a timeout to send "cast" 5 seconds after sending "reel"
setTimeout(function () {
if (reelSent) {
sendMessage('cast');
}
}, 5000);
}
} else if (key === 'fishCaught') {
// If the key is 'fishCaught', handle it using a separate function
handleFishCaught(obj[key]);
}
}
}
function handleFishCaught(fishCaughtData) {
caughtFishList.push(fishCaughtData); // Add the caught fish to the list
console.log(fishCaughtData);
// You can perform additional processing or checks here as needed
}
window.WebSocket = function(url, protocols) {
var ws = protocols ? new OriginalWebSocket(url, protocols) : new OriginalWebSocket(url);
webSockets.push(ws);
ws.addEventListener('message', function(event) {
// Check if the message might be valid JSON (e.g., starts with '{' after removing two characters)
if (event.data.slice(2).trim().startsWith('{')) {
try {
// Remove the first two characters and parse the rest as JSON
var jsonData = JSON.parse(event.data.slice(2))
// Search for "onTheLine" anywhere in the JSON structure
searchOnTheLine(jsonData);
} catch (e) {
console.error('Error processing JSON message:', e);
}
} else {
// If not JSON, you can log or ignore these messages
}
});
return ws;
};
for (var prop in OriginalWebSocket) {
if (OriginalWebSocket.hasOwnProperty(prop)) {
window.WebSocket[prop] = OriginalWebSocket[prop];
}
}
function sendMessage(message) {
if (webSockets.length > 0 && webSockets[0].readyState === WebSocket.OPEN) {
webSockets[0].send(message);
} else {
console.error('No active WebSocket connection found.');
}
}
setTimeout(function() {
sendMessage('cast');
}, 5000);
})();
And here we go with our final fish!
Answer
Catched 171 Fish species.