Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••
AI & KI Nachrichten‘That’s so AI!’ What gen Alpha’s biggest insult tells us(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenCisco’s Jeetu Patel: Never fight a megatrend(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenHow to think about the end of the world(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenChina tries on the smart glasses craze — and its privacy risks(24.09.2026 um 06:00 Uhr)
••
AI & KI NachrichtenThe promise and peril of using visual AI to study cities(24.09.2026 um 06:00 Uhr)
•
Sichere ProgrammierungWe Built a CLI to Find Out If You’re Overpaying for Claude(24.09.2026 um 04:35 Uhr)
•
Sichere ProgrammierungMy own sandbox was killing my agent's shell, and the exit code hid it(24.09.2026 um 04:38 Uhr)
•••
AI & KI Nachrichten‘That’s so AI!’ What gen Alpha’s biggest insult tells us(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenCisco’s Jeetu Patel: Never fight a megatrend(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenHow to think about the end of the world(24.09.2026 um 06:00 Uhr)
•
AI & KI NachrichtenChina tries on the smart glasses craze — and its privacy risks(24.09.2026 um 06:00 Uhr)
••
AI & KI NachrichtenThe promise and peril of using visual AI to study cities(24.09.2026 um 06:00 Uhr)
•
Sichere ProgrammierungWe Built a CLI to Find Out If You’re Overpaying for Claude(24.09.2026 um 04:35 Uhr)
•
Sichere ProgrammierungMy own sandbox was killing my agent's shell, and the exit code hid it(24.09.2026 um 04:38 Uhr)
•
Intelligence View
⚡ tsecurity.de Intelligence

Multiplayer Games with Limn Engine and WebSockets

Multiplayer Games with Limn Engine and WebSockets Building Real-Time Multiplayer Games from Scratch 📖 Introduction Multiplayer gaming is one of the most sought-after features in game development. Players want to compete, co…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Multiplayer Games with Limn Engine and WebSockets



Building Real-Time Multiplayer Games from Scratch









📖 Introduction



Multiplayer gaming is one of the most sought-after features in game development. Players want to compete, cooperate, and connect with others. But building a multiplayer game is notoriously difficult — networking introduces latency, synchronization issues, and a whole new layer of complexity.



In this guide, we'll build a real-time multiplayer game using Limn Engine and WebSockets. We'll cover everything from setting up a WebSocket server to handling player movement, synchronization, and latency compensation.



Note: This is a basic implementation for learning purposes. For production games, you'll need to add authentication, matchmaking, and more robust error handling.









🎯 What We're Building



A simple top-down multiplayer game where:




  • Players connect to a server

  • Each player controls a colored square

  • Players see each other move in real-time

  • Players can see each other's names









🏗️ Architecture Overview






┌─────────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────┐ WebSocket ┌─────────────────────┐ │
│ │ Client 1 │ ◄────────────────► │ │ │
│ └─────────────┘ │ │ │
│ │ Node.js Server │ │
│ ┌─────────────┐ WebSocket │ (ws library) │ │
│ │ Client 2 │ ◄────────────────► │ │ │
│ └─────────────┘ └─────────────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ Client 3 │ ◄────────────────► │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘









How It Works





  1. Clients connect to the server via WebSocket


  2. Server tracks all connected players and their positions


  3. Each client sends their movement updates to the server


  4. Server broadcasts all player positions to all clients


  5. Each client renders all players on their screen









🖥️ Step 1: The WebSocket Server (Node.js)






Install Dependencies






npm init -y
npm install ws









Server Code (server.js)






const WebSocket = require('ws');
const http = require('http');

// ── CONFIGURATION ──
const PORT = 8080;
const WORLD_WIDTH = 2000;
const WORLD_HEIGHT = 2000;

// ── CREATE HTTP SERVER ──
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Multiplayer Server Running</h1>');
});

// ── CREATE WEBSOCKET SERVER ──
const wss = new WebSocket.Server({ server });

// ── GAME STATE ──
const players = {};
let nextId = 1;

// ── HELPER FUNCTIONS ──
function broadcast(data) {
const message = JSON.stringify(data);
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}

function getPlayerState(id) {
return {
id: id,
x: players[id].x,
y: players[id].y,
color: players[id].color,
name: players[id].name
};
}

function getAllPlayerStates() {
const states = {};
for (let id in players) {
states[id] = getPlayerState(id);
}
return states;
}

// ── WEBHOOKS ──
wss.on('connection', (ws) => {
console.log('New player connected');

// Assign player ID
const playerId = nextId++;

// Assign random color
const colors = ['#ff6b6b', '#5b8cff', '#7fffb2', '#ffbb6b', '#ff6bff', '#6bffb2'];
const color = colors[Math.floor(Math.random() * colors.length)];

// Create player
players[playerId] = {
id: playerId,
x: Math.random() * 400 + 200,
y: Math.random() * 400 + 200,
color: color,
name: `Player ${playerId}`
};

// Send current state to new player
ws.send(JSON.stringify({
type: 'init',
playerId: playerId,
players: getAllPlayerStates()
}));

// Broadcast new player to others
broadcast({
type: 'playerJoined',
player: getPlayerState(playerId)
});

// ── HANDLE INCOMING MESSAGES ──
ws.on('message', (message) => {
try {
const data = JSON.parse(message);

if (data.type === 'move') {
// Update player position
players[playerId].x = data.x;
players[playerId].y = data.y;

// Broadcast update to all clients
broadcast({
type: 'playerMoved',
id: playerId,
x: data.x,
y: data.y
});
}

if (data.type === 'chat') {
broadcast({
type: 'chat',
id: playerId,
name: players[playerId].name,
message: data.message
});
}

if (data.type === 'nameChange') {
players[playerId].name = data.name;
broadcast({
type: 'playerNameChanged',
id: playerId,
name: data.name
});
}
} catch (e) {
console.error('Error processing message:', e);
}
});

// ── HANDLE DISCONNECT ──
ws.on('close', () => {
console.log(`Player ${playerId} disconnected`);
delete players[playerId];
broadcast({
type: 'playerLeft',
id: playerId
});
});
});

// ── START SERVER ──
server.listen(PORT, () => {
console.log(`🚀 Multiplayer server running on ws://localhost:${PORT}`);
console.log(`📊 World size: ${WORLD_WIDTH}x${WORLD_HEIGHT}`);
});












🎮 Step 2: The Client (Limn Engine)






Client Code (multiplayer.html)






<!DOCTYPE html>
<html>
<head>
<title>Multiplayer Game - Limn Engine</title>
<script src="epic.js"></script>
<style>
body { margin: 0; background: #0a0a0a; overflow: hidden; }
#status {
position: fixed;
top: 10px;
left: 50%;
transform: translateX(-50%);
color: #7fffb2;
font-family: 'Courier New', monospace;
font-size: 14px;
background: rgba(0,0,0,0.7);
padding: 8px 16px;
border-radius: 8px;
z-index: 1000;
pointer-events: none;
}
#chat {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
width: 400px;
z-index: 1000;
}
#chat-input {
width: 100%;
padding: 8px 12px;
background: rgba(0,0,0,0.8);
color: white;
border: 1px solid #333;
border-radius: 8px;
font-size: 14px;
outline: none;
display: none;
}
#chat-input:focus {
border-color: #7fffb2;
}
#chat-messages {
max-height: 150px;
overflow-y: auto;
margin-bottom: 8px;
color: #aaa;
font-size: 12px;
font-family: 'Courier New', monospace;
}
#chat-messages .system { color: #7fffb2; }
#chat-messages .player { color: #5b8cff; }
</style>
</head>
<body>

<div id="status">🔌 Connecting...</div>

<div id="chat">
<div id="chat-messages"></div>
<input id="chat-input" type="text" placeholder="Press Enter to chat..." />
</div>

<script>
// ── DOM REFS ──
const statusEl = document.getElementById('status');
const chatInput = document.getElementById('chat-input');
const chatMessages = document.getElementById('chat-messages');

// ── LIMN ENGINE SETUP ──
const display = new Display();
display.perform();
display.start(800, 600);
display.backgroundColor("#0a0a10");

// World size
display.camera.worldWidth = 2000;
display.camera.worldHeight = 2000;

// ── GAME STATE ──
let myId = null;
let myName = 'Player';
let remotePlayers = {};
let localPlayer = null;
let isConnected = false;

// ── CREATE LOCAL PLAYER ──
function createLocalPlayer() {
localPlayer = new Component(36, 36, "cyan", 400, 300, "rect");
display.add(localPlayer);
display.camera.follow(localPlayer, true);
return localPlayer;
}

// ── REMOTE PLAYER MANAGEMENT ──
function addRemotePlayer(id, x, y, color, name) {
const player = new Component(36, 36, color, x, y, "rect");
display.add(player);

// Store extra data
player._id = id;
player._name = name || `Player ${id}`;
player._targetX = x;
player._targetY = y;

remotePlayers[id] = player;
return player;
}

function removeRemotePlayer(id) {
if (remotePlayers[id]) {
remotePlayers[id].destroy();
delete remotePlayers[id];
}
}

function updateRemotePlayer(id, x, y) {
if (remotePlayers[id]) {
// Smooth interpolation (lerp) for movement
remotePlayers[id]._targetX = x;
remotePlayers[id]._targetY = y;
}
}

// ── WEBHOOKS SETUP ──
function connectWebSocket() {
const ws = new WebSocket('ws://localhost:8080');

ws.onopen = () => {
isConnected = true;
statusEl.textContent = '✅ Connected!';
statusEl.style.color = '#7fffb2';

// Create local player after receiving initial state
createLocalPlayer();
};

ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
handleMessage(data);
} catch (e) {
console.error('Error parsing message:', e);
}
};

ws.onclose = () => {
isConnected = false;
statusEl.textContent = '❌ Disconnected!';
statusEl.style.color = '#ff6b6b';
setTimeout(() => {
connectWebSocket(); // Auto-reconnect
}, 3000);
};

ws.onerror = (error) => {
console.error('WebSocket error:', error);
statusEl.textContent = '⚠️ Connection error';
statusEl.style.color = '#ffbb6b';
};

// ── MESSAGE HANDLER ──
function handleMessage(data) {
switch (data.type) {
case 'init':
// Set player ID
myId = data.playerId;
statusEl.textContent = `✅ Connected as ${myName}`;

// Add remote players
for (let id in data.players) {
if (parseInt(id) !== myId) {
const p = data.players[id];
addRemotePlayer(id, p.x, p.y, p.color, p.name);
}
}
break;

case 'playerJoined':
if (data.player.id !== myId) {
const p = data.player;
addRemotePlayer(p.id, p.x, p.y, p.color, p.name);
addChatMessage(`👋 ${p.name} joined the game`, 'system');
}
break;

case 'playerLeft':
if (data.id !== myId) {
const name = remotePlayers[data.id]?._name || `Player ${data.id}`;
removeRemotePlayer(data.id);
addChatMessage(`👋 ${name} left the game`, 'system');
}
break;

case 'playerMoved':
if (data.id !== myId) {
updateRemotePlayer(data.id, data.x, data.y);
}
break;

case 'playerNameChanged':
if (data.id !== myId) {
if (remotePlayers[data.id]) {
remotePlayers[data.id]._name = data.name;
}
}
break;

case 'chat':
if (data.id !== myId) {
addChatMessage(`${data.name}: ${data.message}`, 'player');
}
break;
}
}

// ── SEND FUNCTIONS ──
window.sendMove = function(x, y) {
if (isConnected && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'move',
x: x,
y: y
}));
}
};

window.sendChat = function(message) {
if (isConnected && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'chat',
message: message
}));
}
};

window.sendNameChange = function(name) {
if (isConnected && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'nameChange',
name: name
}));
}
};

// ── CHAT UI ──
function addChatMessage(text, type = 'system') {
const div = document.createElement('div');
div.className = type;
div.textContent = text;
chatMessages.appendChild(div);
chatMessages.scrollTop = chatMessages.scrollHeight;

// Limit messages
while (chatMessages.children.length > 50) {
chatMessages.removeChild(chatMessages.firstChild);
}
}

// ── CHAT INPUT HANDLING ──
document.addEventListener('keydown', (e) => {
if (e.key === 't' || e.key === 'T') {
chatInput.style.display = 'block';
chatInput.focus();
}
if (e.key === 'Enter' && chatInput.style.display === 'block') {
const msg = chatInput.value.trim();
if (msg) {
if (msg.startsWith('/name ')) {
const newName = msg.substring(6).trim();
if (newName) {
myName = newName;
sendNameChange(newName);
addChatMessage(`You changed your name to ${newName}`, 'system');
}
} else {
sendChat(msg);
addChatMessage(`${myName}: ${msg}`, 'player');
}
}
chatInput.value = '';
chatInput.style.display = 'none';
}
if (e.key === 'Escape' && chatInput.style.display === 'block') {
chatInput.value = '';
chatInput.style.display = 'none';
}
});

// ── PLAYER NAME INPUT ──
const nameInput = prompt('Enter your name:', `Player ${Math.floor(Math.random() * 1000)}`);
if (nameInput) {
myName = nameInput;
// We'll send the name after connection is established
}

// Wait for connection to send name
const nameCheckInterval = setInterval(() => {
if (isConnected && ws.readyState === WebSocket.OPEN) {
sendNameChange(myName);
clearInterval(nameCheckInterval);
}
}, 100);

// ── GAME LOOP ──
const SPEED = 200;
let lastSendTime = 0;
const SEND_INTERVAL = 50; // ms

function update(dt) {
if (!isConnected || !localPlayer) return;

// Player movement (WASD)
let mx = 0, my = 0;
if (display.keys[87]) my = -1;
if (display.keys[83]) my = 1;
if (display.keys[65]) mx = -1;
if (display.keys[68]) mx = 1;

if (mx !== 0 && my !== 0) {
mx *= 0.707;
my *= 0.707;
}

localPlayer.x += mx * SPEED * dt;
localPlayer.y += my * SPEED * dt;

// Clamp to world
localPlayer.x = Math.max(0, Math.min(1950, localPlayer.x));
localPlayer.y = Math.max(0, Math.min(1950, localPlayer.y));

// Send position to server (throttled)
const now = performance.now();
if (now - lastSendTime > SEND_INTERVAL) {
sendMove(localPlayer.x, localPlayer.y);
lastSendTime = now;
}

// Update remote players (smooth interpolation)
for (let id in remotePlayers) {
const p = remotePlayers[id];
// Smoothly interpolate toward target position
p.x += (p._targetX - p.x) * 0.15;
p.y += (p._targetY - p.y) * 0.15;
}
}

// ── START THE GAME ──
// The update function is now ready
}

// ── INITIALIZE CONNECTION ──
connectWebSocket();

// ── OVERRIDE UPDATE ──
// This is a bit of a hack — we're replacing the global update function
// that Limn Engine expects. In a real game, you'd structure this better.
const originalUpdate = window.update || function() {};
window.update = function(dt) {
// The actual update logic is inside connectWebSocket
// but we need to call it from here
if (typeof updateGame === 'function') {
updateGame(dt);
}
};

// We'll store the update function from the closure
// This is a simplified approach — in production, use a proper module system
let updateGame = function(dt) {};

// Override the connectWebSocket to expose the update function
const originalConnect = connectWebSocket;
connectWebSocket = function() {
// Call the original but capture the update function
// This is a hack — in a real game, use proper architecture
originalConnect();

// Wait for connection to be established
const checkInterval = setInterval(() => {
if (isConnected) {
// Expose the update function
updateGame = function(dt) {
if (!isConnected || !localPlayer) return;

// Player movement (WASD)
let mx = 0, my = 0;
if (display.keys[87]) my = -1;
if (display.keys[83]) my = 1;
if (display.keys[65]) mx = -1;
if (display.keys[68]) mx = 1;

if (mx !== 0 && my !== 0) {
mx *= 0.707;
my *= 0.707;
}

localPlayer.x += mx * SPEED * dt;
localPlayer.y += my * SPEED * dt;

// Clamp to world
localPlayer.x = Math.max(0, Math.min(1950, localPlayer.x));
localPlayer.y = Math.max(0, Math.min(1950, localPlayer.y));

// Send position to server (throttled)
const now = performance.now();
if (now - lastSendTime > SEND_INTERVAL) {
sendMove(localPlayer.x, localPlayer.y);
lastSendTime = now;
}

// Update remote players (smooth interpolation)
for (let id in remotePlayers) {
const p = remotePlayers[id];
p.x += (p._targetX - p.x) * 0.15;
p.y += (p._targetY - p.y) * 0.15;
}
};
clearInterval(checkInterval);
}
}, 100);
};

// Actually start the connection
connectWebSocket();

console.log('🎮 Multiplayer client ready');
console.log('📝 Type /name YourName to change name');
console.log('💬 Press T to chat');
console.log('🕹️ WASD to move');
</script>
</body>
</html>









🎯 Step 3: Running the Game



Start the Server




node server.js






You should see:




🚀 Multiplayer server running on ws://localhost:8080
📊 World size: 2000x2000






Open the Client




  1. Open multiplayer.html in your browser

  2. Enter your name when prompted

  3. Open the same file in another browser tab (or on another device)

  4. Watch both players move in real-time!









📊 Key Concepts Explained






1. WebSocket Communication






































Message Type Sent By Received By Purpose
move Client Server Send player position
playerMoved Server All Clients Broadcast position update
playerJoined Server All Clients New player joined
playerLeft Server All Clients Player disconnected





2. Interpolation (Smooth Movement)






// Smoothly interpolate toward target position
p.x += (p._targetX - p.x) * 0.15;
p.y += (p._targetY - p.y) * 0.15;






This makes remote players move smoothly instead of jumping.






3. Throttled Sending






const SEND_INTERVAL = 50; // ms
if (now - lastSendTime > SEND_INTERVAL) {
sendMove(localPlayer.x, localPlayer.y);
lastSendTime = now;
}






Sending every frame (60 times/sec) would overload the server. Sending 20 times/sec (every 50ms) is enough.









🚀 Extending the Game






Add Player Names Above Heads






// In the render loop
for (let id in remotePlayers) {
const p = remotePlayers[id];
// Draw name above player
display.context.fillStyle = "white";
display.context.font = "12px Arial";
display.context.textAlign = "center";
display.context.fillText(p._name, p.x + 18, p.y - 10);
}









Add Shooting






// Client sends shoot message
function shoot() {
ws.send(JSON.stringify({
type: 'shoot',
x: localPlayer.x + 18,
y: localPlayer.y + 18,
angle: localPlayer.angle || 0
}));
}

// Server broadcasts bullet
broadcast({
type: 'bulletFired',
id: playerId,
x: data.x,
y: data.y,
angle: data.angle
});









Add Score Tracking






// Server tracks scores
players[playerId].score = 0;

// On hit
players[shooterId].score += 10;
broadcast({
type: 'scoreUpdate',
id: shooterId,
score: players[shooterId].score
});












⚠️ Limitations (Not Yet Tested)
































Limitation Description
No authentication Anyone can join with any name
No matchmaking All players join the same world
No room support Can't create separate game rooms
No latency compensation Players with high ping will lag
No reconnection handling If connection drops, progress is lost








🎯 The One-Line Summary




"WebSockets + Limn Engine = real-time multiplayer games with minimal setup."










🔗 Resources








Draw your game into existence — and let others play it too. 🚀

SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - Multiplayer Games with Limn Engine and WebSockets
id: f69ae97f-38da-45a4-81c3-ce91a74804c7
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "Multiplayer Games with Limn En" ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich Multiplayer Games with Limn Engine and W.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Multiplayer Games with Limn Engine and WebSockets

Thematisch verwandte Begriffe: Multiplayer, Games, with, Limn · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96676 | A vulnerability was identified in Fast FAC1900R 20190827_2.0.2. The impa…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger • Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick