diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2df297a --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +<<<<<<< HEAD +node_modules/ +.env +# Compiled source # +################### +.breakpoints +*.com +*.class +*.dll +*.exe +*.o +*.so +out/ +config.json +dist/ +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +node_modules/ +.env +.DS_Store +package-lock.json \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..4154ce2 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node . \ No newline at end of file diff --git a/assets/html/name.html b/assets/html/name.html new file mode 100644 index 0000000..b004c9a --- /dev/null +++ b/assets/html/name.html @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + +Waterwar.io + + + + +
+ +

+

+ +
+ + + +
+ diff --git a/assets/images/bg.jpeg b/assets/images/bg.jpeg new file mode 100644 index 0000000..5dbf214 Binary files /dev/null and b/assets/images/bg.jpeg differ diff --git a/assets/images/redo.png b/assets/images/redo.png new file mode 100644 index 0000000..70563c7 Binary files /dev/null and b/assets/images/redo.png differ diff --git a/assets/images/star-grey.png b/assets/images/star-grey.png new file mode 100644 index 0000000..65138e1 Binary files /dev/null and b/assets/images/star-grey.png differ diff --git a/assets/images/star-medium.png b/assets/images/star-medium.png new file mode 100644 index 0000000..69ee668 Binary files /dev/null and b/assets/images/star-medium.png differ diff --git a/assets/images/star-yellow.png b/assets/images/star-yellow.png new file mode 100644 index 0000000..99b6e2d Binary files /dev/null and b/assets/images/star-yellow.png differ diff --git a/classes/Bridge.js b/classes/Bridge.js new file mode 100644 index 0000000..f230ce1 --- /dev/null +++ b/classes/Bridge.js @@ -0,0 +1,57 @@ +const intersect = require("intersects"); +module.exports = class Bridge { + constructor(island1, island2, width) { + this.island1 = island1; + this.island2 = island2; + this.width = width; + this.length = Math.sqrt(Math.pow(this.island1.pos.x - this.island2.pos.x, 2) + Math.pow(this.island1.pos.y - this.island2.pos.y, 2)); + + // calculate angle + this.angle = Math.atan2(island2.pos.y - island1.pos.y, island2.pos.x - island1.pos.x)+Math.PI/2; + //to degrees + console.log( this.angle * 180 / Math.PI); + } + getSendObject() { + return { + width: this.width, + length: this.length, + angle: this.angle, + pos: this.getCorners()[2], + corners: [this.getCorners()[2]], + }; + } + getCorners(extraDiff = 1) { + // find 4 corners of the bridge, make sure to use the angle and width + var newWidth = this.width * extraDiff; + var corners = []; + corners.push({ + x: this.island1.pos.x + Math.cos(this.angle) * newWidth, + y: this.island1.pos.y + Math.sin(this.angle) * newWidth, + }); + corners.push({ + x: this.island1.pos.x - Math.cos(this.angle) * newWidth, + y: this.island1.pos.y - Math.sin(this.angle) * newWidth, + }); + corners.push({ + x: this.island2.pos.x - Math.cos(this.angle) * newWidth, + y: this.island2.pos.y - Math.sin(this.angle) * newWidth, + }); + corners.push({ + x: this.island2.pos.x + Math.cos(this.angle) * newWidth, + y: this.island2.pos.y + Math.sin(this.angle) * newWidth, + }); + return corners; + } + isIn(player) { + // check if pos is in the bridge + var corners = []; + var u = this.getCorners() + u.forEach(corner => { + corners.push(corner.x); + corners.push(corner.y); + }); + var center = player.getCenterPoint(); + + return intersect.pointPolygon(center.x, center.y, corners); + } +} \ No newline at end of file diff --git a/classes/Bullet.js b/classes/Bullet.js new file mode 100644 index 0000000..b5df46b --- /dev/null +++ b/classes/Bullet.js @@ -0,0 +1,63 @@ +const idgen = require("../helpers/idgen"); +const intersect = require("intersects"); +const io = require("../helpers/io"); + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +class Bullet { + constructor(player, offset) { + this.speed = player.speed / 2; + this.angle = player.lookAngle; + //cloning the object is necessary because the object is changed in the tick function + this.pos = JSON.parse(JSON.stringify(player.pos)); + this.pos.x += (Math.cos(this.angle) * this.speed * (50+offset)); + this.pos.y += (Math.sin(this.angle) * this.speed * (50+offset)); + this.createdAt = Date.now(); + this.owner = player.id; + this.roomId = player.roomId; + this.id = idgen(); + + this.length = 10; + io.getio().to(this.roomId).emit("addBullet", this.getSendObject()); + } + tick(tickDiff) { + this.pos.x += Math.cos(this.angle) * this.speed * 50 * (tickDiff / 50); + this.pos.y += Math.sin(this.angle) * this.speed * 50 * (tickDiff / 50); + } + collidingPlayer(entity) { + if(entity.id == this.owner) return false; + + + + var corners = entity.getCorners(); + var arr = []; + corners.forEach(function(corner) { + arr.push(corner.x); + arr.push(corner.y); + }); + + //check is inside corners + + + return intersect.circlePolygon(this.pos.x, this.pos.y, this.length, arr); + + } + collidingBullet(bullet) { + return intersect.circleCircle(this.pos.x, this.pos.y, this.length, bullet.pos.x, bullet.pos.y, bullet.length); + } + getSendObject() { + return { + pos: this.pos, + id: this.id, + angle: this.angle, + speed: this.speed, + owner: this.owner, + } + } +} + +module.exports = Bullet; \ No newline at end of file diff --git a/classes/Island.js b/classes/Island.js new file mode 100644 index 0000000..2f33d54 --- /dev/null +++ b/classes/Island.js @@ -0,0 +1,90 @@ +const intersect = require("intersects"); +const io = require("../helpers/io"); +const idgen = require("../helpers/idgen"); +module.exports = class Island { + constructor(shape, size, position, canBeCaptured = true) { + this.shape = shape; + this.size = size; + this.pos = position; + this.canBeCaptured = canBeCaptured; + this.capturedBy = "none"; + this.captureState = 0; + this.capturingBy = 0.1; + this.id = idgen(); + this.capturedPercentage = 0; + } + getSendObject() { + return { + shape: this.shape, + size: this.size, + pos: this.pos, + capturedBy: this.capturedBy, + id: this.id, + capturedPercentage: this.capturedPercentage, + capturingBy: this.capturingBy + } + } + tick(diff, room) { + if(!this.canBeCaptured) return; + var players = Array.from(room.players.values()).filter(player => this.isIn(player.pos)); + if(players.length < 1 && this.captureState == 1) { + this.capturedPercentage -= (diff / 50) * 0.5; + if(this.capturedPercentage <= 0) { + this.capturedPercentage = 0; + this.captureState = 0; + } + io.getio().to(room.id).emit("islandCapturing", this.id, this.capturingBy, this.capturedPercentage); + + } + if(players.length < 1 && this.captureState == 2) { + if(this.capturedPercentage >= 100 && this.capturingBy == this.capturedBy) return; + this.capturedPercentage += (diff / 50) * 0.5; + if(this.capturedPercentage >= 100) { + this.capturedBy = this.capturingBy; + this.captureState = 0; + io.getio().to(room.id).emit("islandCaptured", this.id, this.capturedBy); + } else io.getio().to(room.id).emit("islandCapturing", this.id, this.capturingBy, this.capturedPercentage); + + console.log(this.capturedPercentage); + + } + if(players.length < 1) return; + //make sure all players are in the same team + var team = players[0].team; + for(var i = 1; i < players.length; i++) { + if(players[i].team != team) return; + } + if(this.capturedBy == team) return; + console.log(this.captureState); + if(this.captureState == 0) { + this.captureState = 1; + this.capturedPercentage = 0; + this.capturingBy = players[0].team; + console.log(this.capturingBy+ " is capturing island"); + } else if(this.captureState == 1 && this.capturingBy == team) { + this.capturedPercentage += (diff / 50) * players.length; + + if(this.capturedPercentage >= 100) { + this.capturedBy = team; + this.captureState = 2; + io.getio().to(room.id).emit("islandCaptured", this.id, this.capturedBy); + } else { + io.getio().to(room.id).emit("islandCapturing", this.id, this.capturingBy, this.capturedPercentage); + } + + } else if(this.captureState == 2) { + this.capturedPercentage -= (diff / 50) * players.length; + this.capturedBy = "none"; + if(this.capturedPercentage <= 0) { + this.capturedPercentage = 0; + this.captureState = 0; + } + io.getio().to(room.id).emit("islandCaptured", this.id, this.capturedBy); + io.getio().to(room.id).emit("islandCapturing", this.id, this.capturingBy, this.capturedPercentage); + } + + } + isIn(pos) { + return intersect.pointCircle(pos.x, pos.y, this.pos.x, this.pos.y, this.size/2); + } +} \ No newline at end of file diff --git a/classes/Player.js b/classes/Player.js new file mode 100644 index 0000000..ab75b07 --- /dev/null +++ b/classes/Player.js @@ -0,0 +1,146 @@ +const idgen = require("../helpers/idgen"); +const roomlist = require("../helpers/roomlist"); + +const Bullet = require("./Bullet"); + +class Player { + constructor(name, id=idgen(), socket=undefined) { + this.name = name; + this.id = id; + this.roomId = null; + this.socket = socket; + this.pos = { + x: 0, + y: 0, + }; + this.speed = 1; + this.down = false; + + this.bodySize = 50; + + this.team = Math.random() > 0.5 ? "red" : "blue"; + + this.hit = false; + this.lookAngle = 0; + this.bulletIds = new Set(); + this.lastFullSendTo = new Set(); + + this.controller = { + left: false, + right: false, + up: false, + down: false, + }; + } + joinRoom(room) { + this.roomId = room.id; + this.socket.emit("joinRoom", room.id); + } + updateController(controller) { + //check if controller valid + if(controller.left === undefined || controller.right === undefined || controller.up === undefined || controller.down === undefined) { + return; + } + //check if any extra properties are set + if(Object.keys(controller).length > 4) { + return; + } + + this.controller = controller; + } + updateMouse(mouseAngle) { + this.lookAngle = mouseAngle; + } + getFirstSendObject() { + return { + name: this.name, + id: this.id, + speed: this.speed, + team: this.team, + + pos: this.pos, + lookAngle: this.lookAngle + } + } + getSendObject() { + return { + id: this.id, + pos: this.pos, + lookAngle: this.lookAngle, + }; + } + getCorners(extraDiff = 1) { + // get each corner of the player's body + // make sure it's rotated correctly + + var corners = []; + var angle = this.lookAngle+0.785398; + var x = this.pos.x; + var y = this.pos.y; + var length = this.bodySize * extraDiff; + + var cos = Math.cos(angle); + var sin = Math.sin(angle); + + corners.push({ + x: x + cos * length, + y: y + sin * length, + }); + corners.push({ + x: x - cos * length, + y: y - sin * length, + }); + corners.push({ + x: x + sin * length, + y: y - cos * length, + }); + corners.push({ + x: x - sin * length, + y: y + cos * length, + }); + // console.log(corners); + return corners; + + } + getCenterPoint() { + var corners = this.getCorners(); + //find center point + var x = 0; + var y = 0; + for(var i = 0; i < corners.length; i++) { + x += corners[i].x; + y += corners[i].y; + } + x /= corners.length; + y /= corners.length; + return { + x, + y, + } + } + + tick(tickDiff) { + //move + if(this.controller.left) { + this.pos.x -= tickDiff * 0.2 * this.speed; + } + if(this.controller.right) { + this.pos.x += tickDiff * 0.2 * this.speed; + } + if(this.controller.up) { + this.pos.y -= tickDiff * 0.2 * this.speed; + } + if(this.controller.down) { + this.pos.y += tickDiff * 0.2* this.speed; + } + + var corners = this.getCorners(0.5); + // this.socket.emit("corners", [this.pos]) + //shoot + if(!this.down) return; + var room = roomlist.getRoom(this.roomId); + this.down = false; + room.bullets.push(new Bullet(this, 0)); + } +} +module.exports = Player; \ No newline at end of file diff --git a/classes/Room.js b/classes/Room.js new file mode 100644 index 0000000..d31188a --- /dev/null +++ b/classes/Room.js @@ -0,0 +1,174 @@ +const idgen = require("../helpers/idgen"); +const io = require("../helpers/io"); +const intersect = require("intersects"); +const Island = require("./Island"); +const Bridge = require("./Bridge"); + +class Room { + constructor() { + this.id = idgen(); + this.players = new Map(); + this.maxPlayers = 50; + this.lastTick = Date.now(); + this.bullets = []; + this.islands = []; + this.bridges = []; + + this.islands.push(new Island( + "circle", + 1500, + { x: 0, y: 0 }, + false + )); + + this.islands.push(new Island( + "circle", + 500, + { x: 1200, y: 1200 }, + )); + + this.islands.push(new Island( + "circle", + 500, + { x: -1100, y: 1200 }, + )); + + this.islands.push(new Island( + "circle", + 500, + { x: 1500, y: -100 }, + )); + this.islands.push(new Island( + "circle", + 500, + { x: -1400, y: -100 }, + )); + this.islands.push(new Island( + "circle", + 500, + { x: 0, y: -1400 }, + )); + this.bridges.push(new Bridge(this.islands[0], this.islands[1], 100)); + this.bridges.push(new Bridge(this.islands[0], this.islands[2], 100)); + this.bridges.push(new Bridge(this.islands[0], this.islands[3], 100)); + this.bridges.push(new Bridge(this.islands[0], this.islands[4], 100)); + this.bridges.push(new Bridge(this.islands[0], this.islands[5], 100)); + + this.bridges.push(new Bridge(this.islands[1], this.islands[2], 100)); + this.bridges.push(new Bridge(this.islands[2], this.islands[4], 100)); + this.bridges.push(new Bridge(this.islands[4], this.islands[5], 100)); + this.bridges.push(new Bridge(this.islands[5], this.islands[3], 100)); + this.bridges.push(new Bridge(this.islands[3], this.islands[1], 100)); + + + + } + addPlayer(player) { + var ioinstance = io.getio(); + player.joinRoom(this); + this.players.set(player.id, player); + player.socket.join(this.id); + + //TODO: only send players in range + ioinstance.to(this.id).emit("playerJoined", player.getFirstSendObject()); + player.socket.emit("players", [...this.players.values()].map((player) => player.getFirstSendObject())); + player.socket.emit("bullets", this.bullets.map((bullet) => bullet.getSendObject())); + player.socket.emit("islands", this.islands.map((island) => island.getSendObject())); + player.socket.emit("bridges", this.bridges.map((bridge) => bridge.getSendObject())); + } + removePlayer(id) { + var ioinstance = io.getio(); + var player = this.players.get(id); + if(player) { + player.socket.leave(this.id); + this.players.delete(id); + ioinstance.to(this.id).emit("playerLeft", id); + } + } + playerControllerUpdate(id, controller) { + var player = this.players.get(id); + if(player) { + player.updateController(controller); + } + } + playerMouseUpdate(id, mouseAngle) { + var player = this.players.get(id); + if(player) { + if(typeof mouseAngle == "number" && !isNaN(mouseAngle)) { + player.updateMouse(mouseAngle); + } + } + } + playerDown(id, down) { + if(!typeof down == "boolean") return; + var player = this.players.get(id); + if(player) { + player.down = down; + } + } + tick() { + var tickDiff = Date.now() - this.lastTick; + this.lastTick = Date.now(); + var ioinstance = io.getio(); + this.players.forEach((player) => { + + player.tick(tickDiff); + ioinstance.to(this.id).emit("playerUpdate", player.getSendObject(), {hit: player.hit}); + if(player.hit) player.hit = false; + + //make sure player is on island + var inisland = this.islands.some((island) => { + if(island.isIn(player.pos)) { + return true; + } else return false; + }); + if(!inisland) { + var isinbridge = this.bridges.some((bridge) => { + if(bridge.isIn(player)) { + return true; + } else return false; + }); + if(!isinbridge) { + player.socket.emit("youDied", {reason: "drown"}); + ioinstance.to(this.id).emit("playerLeft", player.id); + this.players.delete(player.id); + } + } + }); + this.bullets.forEach((bullet) => { + bullet.tick(tickDiff); + }); + this.bullets = this.bullets.filter((bullet) => { + if(Date.now() - bullet.createdAt > 1000) { + ioinstance.to(this.id).emit("removeBullet", bullet.id); + return false; + } else return true; + }); + this.bullets = this.bullets.filter((bullet) => { + for (var player of Array.from(this.players.values())) { + if(bullet.collidingPlayer(player)) { + player.pos.x += bullet.speed * Math.cos(bullet.angle) * tickDiff * 5; + player.pos.y += bullet.speed * Math.sin(bullet.angle) * tickDiff * 5; + player.hit = true; + ioinstance.to(this.id).emit("removeBullet", bullet.id); + return false; + } + }; + for (var bullet1 of Array.from(this.bullets)) { + if(bullet1.id == bullet.id || bullet.owner == bullet1.owner) continue; + if(bullet.collidingBullet(bullet1)) { + ioinstance.to(this.id).emit("removeBullet", bullet.id); + return false; + } + } + return true; + }); + this.islands.forEach((island) => { + island.tick(tickDiff, this); + }); + + } + +} + +module.exports = Room; \ No newline at end of file diff --git a/helpers/idgen.js b/helpers/idgen.js new file mode 100644 index 0000000..52ae130 --- /dev/null +++ b/helpers/idgen.js @@ -0,0 +1,9 @@ +function gen() { + let id = 0; + return () => { + id += 1; + return id; + }; +} +const curGen = gen(); +module.exports = curGen; diff --git a/helpers/io.js b/helpers/io.js new file mode 100644 index 0000000..c36c9da --- /dev/null +++ b/helpers/io.js @@ -0,0 +1,19 @@ +const { Server } = require("socket.io"); +let io; + +module.exports = { + init: function(server) { + // start socket.io server and cache io value + io = new Server(server, { + cors: { origin: "*" }, + }); + return io; + }, + getio: function() { + // return previously cached value + if (!io) { + throw new Error("must call .init(server) before you can call .getio()"); + } + return io; + } +}; \ No newline at end of file diff --git a/helpers/roomlist.js b/helpers/roomlist.js new file mode 100644 index 0000000..a9408e3 --- /dev/null +++ b/helpers/roomlist.js @@ -0,0 +1,40 @@ +class RoomList { + constructor() { + this.rooms = {}; + } + + getAllRooms() { + return Object.values(this.rooms); + } + + getRoom(id) { + return this.rooms[id]; + } + + setRoom(room) { + this.rooms[room.id] = room; + } + + removeRoom(id) { + delete this.rooms[id]; + } + + getRoomByPlayerId(id) { + for (var room in this.rooms) { + if (this.rooms[room].players.has(id)) { + return this.rooms[room]; + } + } + return null; + } + + tickAll() { + for (var room in this.rooms) { + this.rooms[room].tick(); + } + } +} + +const list = new RoomList(); + +module.exports = list; diff --git a/index.js b/index.js new file mode 100644 index 0000000..707c312 --- /dev/null +++ b/index.js @@ -0,0 +1,74 @@ +const express = require("express"); +var http = require("http"); +require("dotenv").config(); + +const app = express(); +var process = require("process"); + +app.use(express.json()); + +var server = http.createServer(app); +const io = require("./helpers/io").init(server); + +const Player = require("./classes/Player"); +const Room = require("./classes/Room"); + +const roomlist = require("./helpers/roomlist"); + +app.use("/", express.static(__dirname + "/dist")); +app.use("/", express.static(__dirname+"/public")); +app.use("/assets", express.static(__dirname+"/assets")); + +roomlist.setRoom(new Room()) + +io.on("connection", async (socket) => { + socket.on("go", (name) => { + if(!name || typeof name != "string") return; + name = name.trim(); + if(name.length == 0) return socket.disconnect(); + name = name.substring(0,16); + var player = new Player(name, socket.id, socket); + roomlist.getAllRooms()[0].addPlayer(player); + }); + socket.on("controller", (controller) => { + var room = roomlist.getRoomByPlayerId(socket.id); + if(!room) return; + room.playerControllerUpdate(socket.id, controller); + }); + socket.on("mouse", (mouseAngle) => { + var room = roomlist.getRoomByPlayerId(socket.id); + if(!room) return; + room.playerMouseUpdate(socket.id, mouseAngle); + }); + socket.on("down", (down) => { + var room = roomlist.getRoomByPlayerId(socket.id); + if(!room) return; + room.playerDown(socket.id, down); + }) + socket.on("ping", (fn) => { + fn(); // Simply execute the callback on the client + }) + socket.on("disconnect", async () => { + var room = roomlist.getRoomByPlayerId(socket.id); + if(room) { + room.removePlayer(socket.id); + } + }); +}); + +//tick rooms +var tps = 0; +var secondStart = Date.now(); +setInterval(() => { + roomlist.tickAll(); + tps++; + if(Date.now() - secondStart > 1000) { + console.log("tps: " + tps); + tps = 0; + secondStart = Date.now(); + } +}, 1000/20); + +server.listen(process.env.PORT || 3000, () => { + console.log("server started"); +}); diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..2670155 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "include": [ + "src/**/*.js" + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..14d716f --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "waterwar.io", + "version": "1.0.0", + "description": "splash splash splash", + "main": "index.js", + "scripts": { + "build": "webpack --config webpack.config.js", + "prod": "webpack --config webpackprod.config.js", + "watch": "webpack --config webpack.config.js --watch --progress", + "test": "node index.js --unhandled-rejections=strict", + "start": "node index.js --unhandled-rejections=strict" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "dotenv": "^10.0.0", + "express": "^4.17.1", + "intersects": "^2.7.2", + "phaser": "^3.55.2", + "point-in-polygon": "^1.1.0", + "socket.io": "^4.2.0", + "socket.io-client": "^4.5.1", + "ts-loader": "^9.3.0", + "typescript": "^4.6.4", + "uuid": "^8.3.2" + }, + "devDependencies": { + "copy-webpack-plugin": "^10.0.0", + "eslint": "^8.3.0", + "webpack": "^5.61.0", + "webpack-cli": "^4.9.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/codergautam/swordbattle.io.git" + } +} diff --git a/src/GameScene.ts b/src/GameScene.ts new file mode 100644 index 0000000..8b19794 --- /dev/null +++ b/src/GameScene.ts @@ -0,0 +1,279 @@ +import Phaser from "phaser"; +import { io, Socket } from "socket.io-client"; +import Bullet from "./components/Bullet"; +import Island from "./components/Island"; +import GameMap from "./components/Map"; +import Player from "./components/Player"; +import TeamPicker from "./components/TeamPicker"; +import { Data, PlayerData, FirstPlayerData, BulletData, IslandData, BridgeData } from "./helpers/Packets"; + +interface Keys { + up: Phaser.Input.Keyboard.Key; + down: Phaser.Input.Keyboard.Key; + left: Phaser.Input.Keyboard.Key; + right: Phaser.Input.Keyboard.Key; + + w: Phaser.Input.Keyboard.Key; + s: Phaser.Input.Keyboard.Key; + a: Phaser.Input.Keyboard.Key; + d: Phaser.Input.Keyboard.Key; +} + + +class GameScene extends Phaser.Scene { + mobile: boolean; + canvas: { width: number, height: number }; + name: string; + socket: Socket; + loadingText: Phaser.GameObjects.Text; + ready: boolean; + players: Map; + bullets: Map + mouseAngle: number; + map: GameMap; + fpsCounter: Phaser.GameObjects.Text; + controller: {left: boolean, right: boolean, up: boolean, down: boolean}; + islands: Island[]; + uiCam: Phaser.Cameras.Scene2D.Camera; + teamPicker: TeamPicker; + + constructor() { + super("game"); + + } + preload() { + this.loadingText = this.add.text( + this.canvas.width / 2, + this.canvas.height / 2, + "Connecting...", + ).setOrigin(0.5); + this.ready = false; + this.players = new Map(); + this.bullets = new Map(); + this.islands = []; + } + + create() { + this.socket = io(); + this.socket.emit("go", this.name); + + this.map = new GameMap(this); + + this.uiCam = this.cameras.add(0, 0, this.canvas.width, this.canvas.height); + + this.teamPicker = new TeamPicker(this); + + const playerJoined = (data: FirstPlayerData) =>{ + this.players.set(data.id, new Player(this, data.pos.x, data.pos.y, data.id, data.name, data.team).setDepth(2)); + if(this.socket.id === data.id) this.cameras.main.startFollow(this.players.get(data.id)); + } + + this.socket.on("playerJoined", (data: FirstPlayerData) => { + console.log("playerJoined", data); + playerJoined(data); + }); + this.socket.on("playerLeft", (id: string) => { + if(this.players.has(id)){ + this.players.get(id).destroy(); + this.players.delete(id); + } + }); + this.socket.on("players", (data: FirstPlayerData[]) => { + this.ready = true; + this.loadingText.destroy(); + + for (const player of data) { + if(!this.players.has(player.id)) playerJoined(player); + else this.players.get(player.id).tick(player, false); + } + }); + this.socket.on("addBullet", (data: BulletData) => { + if(!this.bullets.has(data.id)) this.bullets.set(data.id, new Bullet(this, data).setDepth(1)); + }); + this.socket.on("removeBullet", (id: string) => { + if(this.bullets.has(id)) { + setTimeout(() => { + this.bullets.get(id).end(); + this.bullets.delete(id); + }, (1000/20)*2); + } + }); + this.socket.on("bullets", (data: BulletData[]) => { + for (const bullet of data) { + if(!this.bullets.has(bullet.id)) this.bullets.set(bullet.id, new Bullet(this, bullet).setDepth(1)); + } + + for (const bullet of this.bullets.values()) { + if(!data.find(b => b.id === bullet.id)) { + setTimeout(() => { + bullet.end(); + this.bullets.delete(bullet.id); + }, (1000/20)*2); + } + } + }); + this.socket.on("islands", (data: IslandData[]) => { + console.log("islands", data); + this.islands = data.map(d => new Island(this, d).setDepth(1)); + }); + + this.socket.on("bridges", (data: BridgeData[]) => { + data.forEach(d => { + var r = this.add.rectangle(d.pos.x, d.pos.y, d.width*2, d.length, 0xffffff).setDepth(0).setRotation(d.angle).setOrigin(0,0); + this.uiCam.ignore(r); + }); + }); + this.socket.on("islandCaptured", (id: number, team: string) => { + console.log("islandCaptured", id, team); + this.islands.find(i => i.id === id).setTeam(team); + + }); + this.socket.on("islandCapturing", (id: number, team: string, percent: number) => { + console.log("islandCapturing", id, team, percent); + this.islands.find(i => i.id === id).setPercent(percent, team); + + }) + // this.socket.on("corners", (data: {x: number, y: number}[]) => { + // data.forEach(d => { + // var el = this.add.ellipse(d.x, d.y, 5, 5, 0x00ff00).setDepth(10); + // setTimeout(() => { + // el.destroy(); + // }, 1000/20); + // }); + // }); + this.socket.on("playerUpdate", (data: PlayerData, object: {hit: boolean}) => { + if(!this.ready) return; + if(!this.players.has(data.id)) return; + this.players.get(data.id).tick(data, object.hit); + }); + // this.socket.on("test", (pos, corners) => { + // console.log(pos); + // this.add.circle(pos.x, pos.y, 5, 0x00FF0F).setOrigin(0.5).setDepth(0); + // this.add.circle(corners[0].x, corners[0].y, 10, 0x00FF00).setOrigin(0.5); + // this.add.circle(corners[1].x, corners[1].y, 10, 0x00FF00).setOrigin(0.5); + // this.add.circle(corners[2].x, corners[2].y, 10, 0x00FF00).setOrigin(0.5); + // this.add.circle(corners[3].x, corners[3].y, 10, 0x00FF00).setOrigin(0.5); + // }) + + this.socket.on("youDied", () => { + this.players.get(this.socket.id).destroy(); + this.players.delete(this.socket.id); + + }) + var keys = (this.input.keyboard.addKeys({ + up: 'up', + down: 'down', + left: 'left', + right: 'right', + w: 'W', + s: 'S', + a: 'A', + d: 'D', + }) as Keys); + + this.controller = { + up: false, + down: false, + left: false, + right: false, + } + + keys.up.on('down', () => { + this.controller.up = true; + this.socket.emit("controller", this.controller); + }); + keys.down.on('down', () => { + this.controller.down = true; + this.socket.emit("controller", this.controller); + }); + keys.left.on('down', () => { + this.controller.left = true; + this.socket.emit("controller", this.controller); + }); + keys.right.on('down', () => { + this.controller.right = true; + this.socket.emit("controller", this.controller); + }); + keys.w.on('down', () => { + this.controller.up = true; + this.socket.emit("controller", this.controller); + }); + keys.s.on('down', () => { + this.controller.down = true; + this.socket.emit("controller", this.controller); + }); + keys.a.on('down', () => { + this.controller.left = true; + this.socket.emit("controller", this.controller); + }); + keys.d.on('down', () => { + this.controller.right = true; + this.socket.emit("controller", this.controller); + }); + + keys.up.on('up', () => { + this.controller.up = false; + this.socket.emit("controller", this.controller); + }); + keys.down.on('up', () => { + this.controller.down = false; + this.socket.emit("controller", this.controller); + }); + keys.left.on('up', () => { + this.controller.left = false; + this.socket.emit("controller", this.controller); + }); + keys.right.on('up', () => { + this.controller.right = false; + this.socket.emit("controller", this.controller); + }); + keys.w.on('up', () => { + this.controller.up = false; + this.socket.emit("controller", this.controller); + }); + keys.s.on('up', () => { + this.controller.down = false; + this.socket.emit("controller", this.controller); + }); + keys.a.on('up', () => { + this.controller.left = false; + this.socket.emit("controller", this.controller); + }); + keys.d.on('up', () => { + this.controller.right = false; + this.socket.emit("controller", this.controller); + }); + + this.mouseAngle = Math.atan2(this.game.input.mousePointer.y - (this.canvas.height /2), this.game.input.mousePointer.x - (this.canvas.width / 2)); + //on mouse move + this.input.on("pointermove", () => { + this.mouseAngle = Math.atan2(this.game.input.mousePointer.y - (this.canvas.height /2), this.game.input.mousePointer.x - (this.canvas.width / 2)) + this.socket.emit("mouse", this.mouseAngle); + }); + + this.input.on("pointerdown", () => { + this.socket.emit("down", true); + }) + this.input.on("pointerup", () => { + this.socket.emit("down", false); + }); + + setInterval(() => { + var start = Date.now(); + this.socket.emit( 'ping', function clientCallback() { + console.log( 'Websocket RTT: ' + (Date.now() - start) + ' ms' ); + }); + }, 2000); + + } + update(time: number, delta: number): void { + Array.from(this.players.values()).forEach(player => player.updateObject()); + Array.from(this.bullets.values()).forEach(bullet => bullet.updateObject()); + + if(!this.fpsCounter) this.fpsCounter = this.add.text(10, 10, "FPS: 0", {color: "white"}).setDepth(0); + this.cameras.main.ignore(this.fpsCounter); + this.fpsCounter.setText("FPS: " + this.game.loop.actualFps.toFixed(2)); + } +} + +export default GameScene; \ No newline at end of file diff --git a/src/OpenScene.ts b/src/OpenScene.ts new file mode 100644 index 0000000..cc7d307 --- /dev/null +++ b/src/OpenScene.ts @@ -0,0 +1,44 @@ +import Phaser from "phaser"; + +class OpenScene extends Phaser.Scene { + callback: any; + e: boolean; + background: Phaser.GameObjects.Rectangle; + loadText: Phaser.GameObjects.Text; + canvas: any; + mobile: boolean; + constructor() { + super("open"); + } + preload() { + console.time("load"); + this.e = true; + this.background = this.add.rectangle(0, 0, document.documentElement.clientWidth, document.documentElement.clientHeight, 0x2e74e6).setOrigin(0).setScrollFactor(0, 0).setScale(2); + this.loadText = this.add.text(0,0,"Loading").setOrigin(0.5,0.5); + + this.loadText.setFontSize(this.canvas.width/20); + this.loadText.x = this.canvas.width/2; + this.loadText.y = this.canvas.height/2; + + //load images + + this.load.image("title", "/assets/images/bg.jpeg"); + + this.load.html("namebox", "/assets/html/name.html"); + + this.scale.fullscreenTarget = document.getElementById("game"); + console.timeEnd("load"); + + } + + create() { + + this.scene.stop(); + this.scene.start("title"); + } + update() { + + } +} + +export default OpenScene; \ No newline at end of file diff --git a/src/TitleScene.ts b/src/TitleScene.ts new file mode 100644 index 0000000..9f2c34b --- /dev/null +++ b/src/TitleScene.ts @@ -0,0 +1,69 @@ +import Phaser from "phaser"; + +class TitleScene extends Phaser.Scene { + callback: Function; + nameBox: Phaser.GameObjects.DOMElement; + canvas: { width: number, height: number }; + background: Phaser.GameObjects.Image; + text: Phaser.GameObjects.Text; + mobile: boolean; + constructor(callback: Function) { + super("title"); + this.callback = callback; + } + preload() { + } + create() { + this.nameBox = this.add.dom(0,0).createFromCache("namebox"); + this.background = this.add.image(0, 0, "title").setOrigin(0).setScrollFactor(0, 0).setScale(2); + + this.text = this.add.text(this.canvas.width / 2, 0, "Waterwar.io", { + fontSize: "64px", + color: "#000000", + }).setOrigin(0.5); + + this.nameBox.getChildByName("btn").addEventListener("click", () => { + var box = this.nameBox.getChildByName("name") as HTMLInputElement | null; + var name = box.value.trim(); + if(!name || name.length == 0) return; + + this.callback(name); + }); + + + //this.stats.y -= this.stats.height + + const resize = () => { + + this.game.scale.resize(this.canvas.width, this.canvas.height); + + try { + const cameraWidth = this.cameras.main.width; + const cameraHeight = this.cameras.main.height; + this.background.setScale(Math.max(cameraWidth / this.background.width, cameraHeight / this.background.height)); + + this.background.x = 0 - ((this.background.displayWidth - cameraWidth) / 2); + } catch (e) { + + } + this.text.x = this.canvas.width / 2; + this.text.y = this.canvas.height / 4; + + this.nameBox.x = this.canvas.width / 2; + this.nameBox.y = this.canvas.height / 2.3; + }; + var doit: string | number | NodeJS.Timeout; + + window.addEventListener("resize", function() { + clearTimeout(doit); + doit = setTimeout(resize, 100); + }); + + resize(); + } + update(time: number, delta: number): void { + this.text.setFontSize(Math.min(this.canvas.width/12, this.canvas.height/5)); + } +} + +export default TitleScene; diff --git a/src/components/Bullet.ts b/src/components/Bullet.ts new file mode 100644 index 0000000..fc281eb --- /dev/null +++ b/src/components/Bullet.ts @@ -0,0 +1,49 @@ +import Phaser from "phaser"; +import GameScene from "../GameScene"; +import { BulletData, Data } from "../helpers/Packets"; + +export default class Bullet extends Phaser.GameObjects.Container { + id: string; + bullet: Phaser.GameObjects.Rectangle; + lastRecievedData: number; + goTo: { x: number; y: number; }; + speed: number; + mAngle: number; + lastUpdate: number; + constructor(scene: Phaser.Scene, data: BulletData) { + super(scene); + this.id = data.id; + this.x = data.pos.x; + this.y = data.pos.y; + + this.speed = data.speed; + this.mAngle = data.angle; + + this.goTo = { + x: data.pos.x, + y: data.pos.y + } + + + this.bullet = new Phaser.GameObjects.Ellipse(scene, 0, 0, 20, 20, 0x00FFFF).setOrigin(0.5); + this.bullet.setRotation(data.angle+(Math.PI/2)); + this.lastRecievedData = Date.now(); + this.add(this.bullet); + (this.scene as GameScene).uiCam.ignore(this); + this.scene.add.existing(this); + + this.lastUpdate = Date.now(); + + // this.visible = false; + } + end() { + this.destroy(); + } + updateObject() { + + this.x += Math.cos(this.mAngle) * this.speed * 50 * ((Date.now() - this.lastUpdate) / 50); + this.y += Math.sin(this.mAngle) * this.speed * 50 * ((Date.now() - this.lastUpdate) / 50); + this.lastUpdate = Date.now(); + + } +} \ No newline at end of file diff --git a/src/components/Island.ts b/src/components/Island.ts new file mode 100644 index 0000000..0c17ab1 --- /dev/null +++ b/src/components/Island.ts @@ -0,0 +1,44 @@ +import GameScene from "../GameScene"; +import { IslandData } from "../helpers/Packets"; +export default class Island extends Phaser.GameObjects.Container { + island: Phaser.GameObjects.Ellipse; + shape: string; + capturedBy: string; + id: number; + capturingCircle: Phaser.GameObjects.Ellipse; + constructor(scene: Phaser.Scene, data: IslandData) { + super(scene); + this.x = data.pos.x; + this.y = data.pos.y; + this.shape = data.shape; + this.capturedBy = data.capturedBy; + this.capturingCircle = new Phaser.GameObjects.Ellipse(scene, 0, 0, data.size, data.size, 0x00FFFF).setOrigin(0.5).setVisible(false).setDepth(1); + this.id = data.id; + + if(this.capturedBy == "red") console.log(this.id + " is captured by red"); + this.island = new Phaser.GameObjects.Ellipse(scene, 0, 0, data.size, data.size, data.capturedBy == "none" ? 0x838579: data.capturedBy == "red" ? 0xFF0000 : 0x0000FF).setOrigin(0.5).setDepth(1); + + if(data.capturedPercentage < 100) { + this.setPercent(data.capturedPercentage, data.capturingBy); + } + + this.add(this.island); + this.add(this.capturingCircle); + this.scene.add.existing(this); + (this.scene as GameScene).uiCam.ignore(this); + } + + setTeam(team: string) { + this.capturingCircle.setVisible(false); + this.island.setFillStyle(team == "red" ? 0xFF0000 : team == "none" ? 0x838579 : 0x0000FF); + this.capturedBy = team; + } + setPercent(percent: number, team: string) { + console.log(team) + this.capturingCircle.setFillStyle(team == "red" ? 0xFF0000 : team == "none" ? 0x838579 : 0x0000FF); + this.capturingCircle.setVisible(true); + this.capturingCircle.setScale(percent/100); + } + +} + diff --git a/src/components/Map.ts b/src/components/Map.ts new file mode 100644 index 0000000..07cd811 --- /dev/null +++ b/src/components/Map.ts @@ -0,0 +1,16 @@ +import Phaser from "phaser"; + +export default class GameMap extends Phaser.GameObjects.Container { + islands: Phaser.GameObjects.Rectangle[]; + constructor(scene: Phaser.Scene) { + super(scene); + + this.scene.add.existing(this); + } + end() { + + } + updateObject() { + + } +} \ No newline at end of file diff --git a/src/components/Player.ts b/src/components/Player.ts new file mode 100644 index 0000000..0ad6504 --- /dev/null +++ b/src/components/Player.ts @@ -0,0 +1,94 @@ +import Phaser from "phaser"; +import GameScene from "../GameScene"; +import { PlayerData } from "../helpers/Packets"; +export default class Player extends Phaser.GameObjects.Container { + square: Phaser.GameObjects.Rectangle; + gun: Phaser.GameObjects.Rectangle; + bodySize: number; + lastTick: number; + toAngle: number; + lastUpdate: number; + id: string; + name: string; + speed: number; + team: string; + nameTag: Phaser.GameObjects.Text; + constructor(scene: Phaser.Scene, x: number, y: number, id: string, name: string, team: string, speed: number = 1, size: number = 50) { + super(scene); + this.x = x; + this.y = y; + this.bodySize = size; + this.lastTick = Date.now(); + this.lastUpdate = Date.now(); + + this.id = id; + this.name = name; + this.speed = speed; + + this.team = team; + // alert(size)/ + this.square = new Phaser.GameObjects.Rectangle(scene, 0, 0, this.bodySize, this.bodySize, team == "red" ? 0x013220: 0x0000FF).setOrigin(0.5); + this.gun = new Phaser.GameObjects.Rectangle(scene, 0, 0, this.bodySize/2, this.bodySize/2, team == "red" ? 0xff0000 : 0x00FFFF).setOrigin(0.5); + this.nameTag = new Phaser.GameObjects.Text(scene, 0, -1 * this.square.displayHeight, name, { + fontSize: "20px", + color: team == "red" ? "#ff0000" : "#00FFFF", + align: "center" + }).setDepth(5).setOrigin(0.5); + + this.toAngle =this.square.rotation; + + this.add(this.square); + this.add(this.gun); + if(this.id != (this.scene as GameScene).socket.id) this.add(this.nameTag); + this.scene.add.existing(this); + (this.scene as GameScene).uiCam.ignore(this); + } + tick(data: PlayerData, hit: boolean) { + this.toAngle = data.lookAngle; + this.scene.tweens.add({ + targets: this, + x: data.pos.x, + y: data.pos.y, + duration: hit ? 500 : 100, + ease: "Power2", + repeat: 0, + yoyo: false, + }); + + + this.lastTick = Date.now(); + + } + updateObject() { + var tickDiff = Date.now() - this.lastUpdate; + function rLerp (A: number, B: number, w: number){ + let CS = (1-w)*Math.cos(A) + w*Math.cos(B); + let SN = (1-w)*Math.sin(A) + w*Math.sin(B); + return Math.atan2(SN,CS); + } + + if((this.scene as GameScene).socket.id != this.id) this.square.setRotation(rLerp(this.square.rotation, this.toAngle, 0.5)); + else this.square.setRotation((this.scene as GameScene).mouseAngle); + + this.gun.setRotation(this.square.rotation); + this.gun.x = Math.cos(this.square.rotation) * this.bodySize/2; + this.gun.y = Math.sin(this.square.rotation) * this.bodySize/2; + + if(this.id == (this.scene as GameScene).socket.id) { + var controller = (this.scene as GameScene).controller; + if(controller.left) { + this.x -= tickDiff * 0.2 * this.speed; + } + if(controller.right) { + this.x += tickDiff * 0.2 * this.speed; + } + if(controller.up) { + this.y -= tickDiff * 0.2 * this.speed; + } + if(controller.down) { + this.y += tickDiff * 0.2* this.speed; + } + this.lastUpdate = Date.now(); + } + } +} \ No newline at end of file diff --git a/src/components/TeamPicker.ts b/src/components/TeamPicker.ts new file mode 100644 index 0000000..f348331 --- /dev/null +++ b/src/components/TeamPicker.ts @@ -0,0 +1,18 @@ +import Phaser, { Game, Scene } from "phaser"; +import GameScene from "../GameScene"; +export default class ClassPicker extends Phaser.GameObjects.Container { + rect1: Phaser.GameObjects.Rectangle; + constructor(scene: GameScene) { + super(scene as Scene); + + +this.rect1 = new Phaser.GameObjects.Rectangle(scene, scene.canvas.width / 2, (scene.canvas.height / 4), 100, 100, 0x00FFFF); +this.add(this.rect1); +this.scene.add.existing(this); +this.scene.cameras.main.ignore(this); + } + update() { + // console.log("ClassPicker update"); + + } +} \ No newline at end of file diff --git a/src/helpers/Packets.ts b/src/helpers/Packets.ts new file mode 100644 index 0000000..1be390d --- /dev/null +++ b/src/helpers/Packets.ts @@ -0,0 +1,35 @@ +interface Data { + id: string; + pos: {x: number, y: number}; +} +interface PlayerData extends Data { + lookAngle: number; +} +interface FirstPlayerData extends PlayerData { + name: string; + team: string; +} +interface BulletData extends Data { + angle: number; + speed: number; + owner: string; +} +interface IslandData { + pos: {x: number, y: number}; + id: number; + shape: string; + capturedBy: string; + size: number; + capturedPercentage: number; + capturingBy: string; +} +interface BridgeData { + width: number, + length: number, + angle: number, + pos: {x: number, y: number}, + corners: {x: number, y: number}[], +}; + + +export { Data, BridgeData, IslandData, BulletData, PlayerData, FirstPlayerData }; \ No newline at end of file diff --git a/src/helpers/msToSeconds.ts b/src/helpers/msToSeconds.ts new file mode 100644 index 0000000..edbf4a4 --- /dev/null +++ b/src/helpers/msToSeconds.ts @@ -0,0 +1,3 @@ +export default function msToSeconds(ms: number) { + return Math.ceil(ms / 1000).toString(); +} diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..71268b8 --- /dev/null +++ b/src/index.html @@ -0,0 +1,42 @@ + + + + + + + + + + + Waterwar.io + + +
+ + + + + diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..cc41352 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,79 @@ +import TitleScene from "./TitleScene"; +import OpenScene from "./OpenScene"; +import GameScene from "./GameScene"; +import Phaser from "phaser"; + +window.addEventListener("load", () => { +var config = { + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight, + parent: "game", + dom: { + createContainer: true, + autoCenter: Phaser.Scale.CENTER_BOTH, + }, + scale: { + mode:Phaser.Scale.RESIZE, + } + +}; +var mobile = window.matchMedia("(pointer: coarse)").matches; +var game = new Phaser.Game(config); + +var openScene = new OpenScene(); +var gameScene = new GameScene(); + + +//alert(lastAd) +var scale = "scale(1)"; // IE 9 + document.body.style.transform = scale; // General + + +var titleScene = new TitleScene((name: string) => { + gameScene.name = name; + game.scene.switch("title", "game"); + return name; +}); + +titleScene.mobile = mobile; +openScene.mobile = mobile; +gameScene.mobile = mobile; +//titleScene.showPromo = false; + +function canvas() { + return { + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight + }; +} + +Object.defineProperty(titleScene, "canvas", { + get: canvas +}); +Object.defineProperty(openScene, "canvas", { + get: canvas +}); +Object.defineProperty(gameScene, "canvas", { + get: canvas +}); + + + +game.scene.add("title", titleScene); +game.scene.add("open", openScene); +game.scene.add("game", gameScene); + +game.scene.start("open"); + +document.addEventListener("contextmenu",function(e) { + e.preventDefault(); +}); + + +//for debugging on the school chromebooks they fricking banned dev console +/*window.onerror = function(msg, url, line) { + document.write("Error : " + msg + "

"); + document.write("Line number : " + line + "

"); + document.write("File : " + url); +};*/ +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..76b973e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "sourceMap": true, + "esModuleInterop": true, + "target": "es5", + "downlevelIteration": true + }, +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..bc24500 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,42 @@ + +//const webpack = require("webpack"); +const path = require("path"); +const CopyPlugin = require("copy-webpack-plugin"); +function uuidv4() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} +const config = { + entry: "./src/index.ts", + plugins: [ + new CopyPlugin({ + patterns: [ + { from: "src/index.html", to: "", transform(content) { + return content + .toString() + .replace("RANDOM_UUID", uuidv4()); + }}, + ], + }), + ], + resolve: { + // Add `.ts` and `.tsx` as a resolvable extension. + extensions: [".ts", ".tsx", ".js"] + }, + module: { + rules: [ + // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader` + { test: /\.tsx?$/, loader: "ts-loader" } + ] + }, + output: { + path: path.resolve(__dirname, "dist"), + filename: "main.js", + }, + devtool: "source-map", + mode: "development" +}; + +module.exports = config; diff --git a/webpackprod.config.js b/webpackprod.config.js new file mode 100644 index 0000000..1c0d64e --- /dev/null +++ b/webpackprod.config.js @@ -0,0 +1,44 @@ + +//const webpack = require("webpack"); +const path = require("path"); +const CopyPlugin = require("copy-webpack-plugin"); +const {CAPTCHASITE} = require("./config.json"); +function uuidv4() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} +const config = { + entry: "./src/index.ts", + plugins: [ + new CopyPlugin({ + patterns: [ + { from: "src/index.html", to: "", transform(content) { + return content + .toString() + .replace("INSERT_RECAPTCHA_SITE_KEY", CAPTCHASITE) + .replace("RANDOM_UUID", uuidv4()); + }}, + ], + }), + ], + resolve: { + // Add `.ts` and `.tsx` as a resolvable extension. + extensions: [".ts", ".tsx", ".js"] + }, + module: { + rules: [ + // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader` + { test: /\.tsx?$/, loader: "ts-loader" } + ] + }, + output: { + path: path.resolve(__dirname, "dist"), + filename: "main.js", + }, + devtool: "source-map", + mode: "production" +}; + +module.exports = config;