Skip to content

Commit

Permalink
Add player ping icon. Also setting up for other icons.
Browse files Browse the repository at this point in the history
  • Loading branch information
kylepaulsen committed Apr 13, 2021
1 parent efb821a commit c1b532c
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 107 deletions.
8 changes: 6 additions & 2 deletions WebMap/MapDataServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class MapDataServer {
private HttpServer httpServer;
private string publicRoot;
private Dictionary<string, byte[]> fileCache;
private Timer broadcastTimer;
private System.Threading.Timer broadcastTimer;
private WebSocketServiceHost webSocketHandler;

public byte[] mapImageData;
Expand All @@ -54,7 +54,7 @@ public MapDataServer() {

webSocketHandler = httpServer.WebSocketServices["/"];

broadcastTimer = new Timer((e) => {
broadcastTimer = new System.Threading.Timer((e) => {
var dataString = "";
players.ForEach(player => {
var zdoData = ZDOMan.instance.GetZDO(player.m_characterID);
Expand Down Expand Up @@ -172,5 +172,9 @@ public void ListenAsync() {
Debug.Log("!!! HTTP Server Failed To Start !!!");
}
}

public void BroadcastPing(long id, string name, Vector3 position) {
webSocketHandler.Sessions.Broadcast($"ping\n{id}\n{name}\n{position.x},{position.z}");
}
}
}
68 changes: 56 additions & 12 deletions WebMap/WebMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using BepInEx;
using UnityEngine;
using HarmonyLib;
using static ZRoutedRpc;

namespace WebMap {
//This attribute is required, and lists metadata for your plugin.
Expand Down Expand Up @@ -91,18 +92,23 @@ public void UpdateFogTexture() {

mapDataServer.players.ForEach(player => {
if (player.m_publicRefPos) {
var zdoData = ZDOMan.instance.GetZDO(player.m_characterID);
var pos = zdoData.GetPosition();
var pixelX = Mathf.RoundToInt(pos.x / PIXEL_SIZE + halfTextureSize);
var pixelY = Mathf.RoundToInt(pos.z / PIXEL_SIZE + halfTextureSize);
for (var y = pixelY - pixelExploreRadius; y <= pixelY + pixelExploreRadius; y++) {
for (var x = pixelX - pixelExploreRadius; x <= pixelX + pixelExploreRadius; x++) {
if (y >= 0 && x >= 0 && y < TEXTURE_SIZE && x < TEXTURE_SIZE) {
var xDiff = pixelX - x;
var yDiff = pixelY - y;
var currentExploreRadiusSquared = xDiff * xDiff + yDiff * yDiff;
if (currentExploreRadiusSquared < pixelExploreRadiusSquared) {
mapDataServer.fogTexture.SetPixel(x, y, Color.white);
ZDO zdoData = null;
try {
zdoData = ZDOMan.instance.GetZDO(player.m_characterID);
} catch {}
if (zdoData != null) {
var pos = zdoData.GetPosition();
var pixelX = Mathf.RoundToInt(pos.x / PIXEL_SIZE + halfTextureSize);
var pixelY = Mathf.RoundToInt(pos.z / PIXEL_SIZE + halfTextureSize);
for (var y = pixelY - pixelExploreRadius; y <= pixelY + pixelExploreRadius; y++) {
for (var x = pixelX - pixelExploreRadius; x <= pixelX + pixelExploreRadius; x++) {
if (y >= 0 && x >= 0 && y < TEXTURE_SIZE && x < TEXTURE_SIZE) {
var xDiff = pixelX - x;
var yDiff = pixelY - y;
var currentExploreRadiusSquared = xDiff * xDiff + yDiff * yDiff;
if (currentExploreRadiusSquared < pixelExploreRadiusSquared) {
mapDataServer.fogTexture.SetPixel(x, y, Color.white);
}
}
}
}
Expand Down Expand Up @@ -293,5 +299,43 @@ static void Postfix(List<ZNetPeer> ___m_peers) {
mapDataServer.players = ___m_peers;
}
}

private static readonly int sayMethodHash = "Say".GetStableHashCode();
private static readonly int chatMessageMethodHash = "ChatMessage".GetStableHashCode();

[HarmonyPatch(typeof (ZRoutedRpc), "HandleRoutedRPC")]
private class ZRoutedRpcPatch {
static void Prefix(RoutedRPCData data) {
if (data?.m_methodHash == sayMethodHash) {
try {
ZPackage package = new ZPackage(data.m_parameters.GetArray());
int messageType = package.ReadInt();
string userName = package.ReadString();
string message = package.ReadString();
message = (message == null ? "" : message).Trim();

Debug.Log("SAY!!! " + messageType + " | " + userName + " | " + message);
} catch (Exception e) {
Debug.Log("Failed processing RoutedRPCData" + e);
}
} else if (data?.m_methodHash == chatMessageMethodHash) {
try {
ZPackage package = new ZPackage(data.m_parameters.GetArray());
Vector3 pos = package.ReadVector3();
int messageType = package.ReadInt();
string userName = package.ReadString();
// string message = package.ReadString();
// message = (message == null ? "" : message).Trim();

if (messageType == 3) {
mapDataServer.BroadcastPing(data.m_senderPeerID, userName, pos);
}
// Debug.Log("CHAT!!! " + pos + " | " + messageType + " | " + userName + " | " + message);
} catch (Exception e) {
Debug.Log("Failed processing RoutedRPCData" + e);
}
}
}
}
}
}
3 changes: 3 additions & 0 deletions WebMap/WebMap.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
<Reference Include="assembly_valheim">
<HintPath>..\libs\assembly_valheim.dll</HintPath>
</Reference>
<Reference Include="assembly_utils">
<HintPath>..\libs\assembly_utils.dll</HintPath>
</Reference>
<Reference Include="BepInEx">
<HintPath>..\libs\BepInEx.dll</HintPath>
</Reference>
Expand Down
3 changes: 2 additions & 1 deletion WebMap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"version": "1.0.0",
"description": "A Valheim map viewer for the browser",
"scripts": {
"build": "webpack ./web-src/index.js -o ./web --mode production"
"build": "webpack ./web-src/index.js -o ./web --mode development",
"build-prod": "webpack ./web-src/index.js -o ./web --mode production"
},
"author": "Kyle Paulsen <[email protected]>",
"license": "ISC",
Expand Down
27 changes: 26 additions & 1 deletion WebMap/web-src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const fetchFog = () => new Promise((res) => {

const setup = async () => {
websocket.init();
players.init({ canvas: map.canvas });
players.init();

await Promise.all([
fetchMap(),
Expand All @@ -30,6 +30,31 @@ const setup = async () => {
mapImage,
fogImage
});

const pings = {};
websocket.addActionListener('ping', (ping) => {
let mapIcon = pings[ping.playerId];
if (!mapIcon) {
mapIcon = { ...ping };
mapIcon.type = 'ping';
mapIcon.text = ping.name;
map.addIcon(mapIcon, false);
pings[ping.playerId] = mapIcon;
}
mapIcon.x = ping.x;
mapIcon.y = ping.y;
map.updateIcons();

clearTimeout(mapIcon.timeoutId);
mapIcon.timeoutId = setTimeout(() => {
delete pings[ping.playerId];
map.removeIcon(mapIcon);
}, 8000);
});

window.addEventListener('resize', () => {
map.update();
});
};

setup();
83 changes: 68 additions & 15 deletions WebMap/web-src/map.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import ui from './ui';
import constants from "./constants";
import playerManager from "./players";
import websocket from "./websocket";
import onPointers from "./onPointers";

const { canvas } = ui;
Expand All @@ -12,6 +10,10 @@ const exploreRadius = constants.EXPLORE_RADIUS;
const pixelSize = constants.PIXEL_SIZE;
const coordOffset = constants.COORD_OFFSET;

// preload map icons.
const mapIconImage = document.createElement('img');
mapIconImage.src = 'mapIcons.png';

canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
Expand All @@ -30,24 +32,72 @@ fogCanvasCtx.fillStyle = '#ffffff';

let currentZoom = 100;

const updateFog = () => {
const radius = exploreRadius / pixelSize;
playerManager.players.forEach(player => {
const x = player.x / pixelSize + coordOffset;
const y = height - (player.y / pixelSize + coordOffset);
fogCanvasCtx.beginPath();
fogCanvasCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
fogCanvasCtx.fill();
const mapIcons = [];

const createIconEl = (iconObj) => {
const iconEl = document.createElement('div');
iconEl.id = iconObj.id;
iconEl.className = `mapIcon ${iconObj.type}`;
const iconTextEl = document.createElement('div');
iconTextEl.textContent = iconObj.text;
iconEl.appendChild(iconTextEl);
return iconEl;
};

const updateIcons = () => {
const canvasOffsetScale = canvas.offsetWidth / width;

mapIcons.forEach(iconObj => {
let iconElement = document.getElementById(iconObj.id);
if (!iconElement) {
iconElement = createIconEl(iconObj);
document.body.appendChild(iconElement);
}
const adjustX = (iconElement.offsetWidth / 2);
const adjustY = (iconElement.offsetHeight / 2);
const imgX = iconObj.x / pixelSize + coordOffset;
const imgY = height - (iconObj.y / pixelSize + coordOffset);

iconElement.style.left = (imgX * canvasOffsetScale + canvas.offsetLeft) - adjustX + 'px';
iconElement.style.top = (imgY * canvasOffsetScale + canvas.offsetTop) - adjustY + 'px';
});
};

const addIcon = (iconObj, update = true) => {
if (!iconObj.id) {
iconObj.id = `id_${Date.now()}_${Math.random()}`;
}
mapIcons.push(iconObj);
if (update) {
updateIcons();
}
};

const removeIcon = (iconObj) => {
mapIcons.splice(mapIcons.indexOf(iconObj), 1);
const iconElement = document.getElementById(iconObj.id);
if (iconElement) {
iconElement.remove();
}
};

const explore = (mapX, mapY) => {
const radius = exploreRadius / pixelSize;
const x = mapX / pixelSize + coordOffset;
const y = height - (mapY / pixelSize + coordOffset);
fogCanvasCtx.beginPath();
fogCanvasCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
fogCanvasCtx.fill();
};

const redrawMap = () => {
ctx.clearRect(0, 0, width, height);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(mapImage, 0, 0);
ctx.globalCompositeOperation = 'multiply';
updateFog();
ctx.drawImage(fogCanvas, 0, 0);

updateIcons();
};

const setZoom = function(zoomP) {
Expand All @@ -66,8 +116,6 @@ const init = (options) => {

redrawMap();

websocket.addActionListener('players', redrawMap);

const zoomChange = (e, mult = 1) => {
const oldZoom = currentZoom;

Expand All @@ -84,7 +132,7 @@ const init = (options) => {

canvas.style.left = zoomRatio * (canvas.offsetLeft - e.clientX) + e.clientX + 'px';
canvas.style.top = zoomRatio * (canvas.offsetTop - e.clientY) + e.clientY + 'px';
playerManager.redrawPlayers();
updateIcons();
};

window.addEventListener('wheel', zoomChange);
Expand All @@ -107,7 +155,7 @@ const init = (options) => {
const e = pointers[0].event;
canvas.style.left = canvasPreDragPos.x + (e.clientX - pointers[0].downEvent.clientX) + 'px';
canvas.style.top = canvasPreDragPos.y + (e.clientY - pointers[0].downEvent.clientY) + 'px';
playerManager.redrawPlayers();
updateIcons();
} else if (pointers.length === 2) {
const x1 = pointers[0].event.clientX;
const y1 = pointers[0].event.clientY;
Expand Down Expand Up @@ -137,6 +185,11 @@ const init = (options) => {

export default {
init,
addIcon,
removeIcon,
explore,
update: redrawMap,
updateIcons,
canvas
};

Loading

0 comments on commit c1b532c

Please sign in to comment.