ソースを参照

Add tools

Include tools for testing various parts of the app
feature/data-structs
コミット
938b9c1250
8個のファイルの変更448行の追加1行の削除
  1. +0
    -0
      assets/sfx/weapons/guns/smg-hkmp5a3/1_unload_var0.wav
  2. +0
    -0
      assets/sfx/weapons/guns/smg-hkmp5k/1_unload_var0.wav
  3. +1
    -1
      docs/weapons.md
  4. +60
    -0
      tools/audio-interval-test/index.html
  5. +57
    -0
      tools/audio-interval-test/index.js
  6. +1
    -0
      tools/audio-interval-test/sfx
  7. +180
    -0
      tools/websocket-client/index.html
  8. +149
    -0
      tools/websocket-client/index.js

assets/sfx/weapons/guns/smg-hkmp5a3/1_unload.wav → assets/sfx/weapons/guns/smg-hkmp5a3/1_unload_var0.wav ファイルの表示


assets/sfx/weapons/guns/smg-hkmp5k/1_unload.wav → assets/sfx/weapons/guns/smg-hkmp5k/1_unload_var0.wav ファイルの表示


+ 1
- 1
docs/weapons.md ファイルの表示

@@ -3,7 +3,7 @@
| Combat knife | Combat knife | - | | - | - |
| Oriental sword | Katana | - | | - | - |
| Twin pistols | Beretta M9 | 9x19mm Parabellum | 15 | - | 381 |
| Shotgun | Ithaca Model 37 | 12 gauge 2.75" shells | 8 | - | - |
| Shotgun | Ithaca Model 37 | 12 gauge 2.75" shells | 8 | - | 410 |
| Sub-machine gun | H&K MP5A3 | 9x19mm Parabellum | 30 | 800 (cyclic) | 400 |
| Sub-machine gun | H&K MP5K | 9x19mm Parabellum | 30 | 900 (cyclic) | 375 |
| Sub-machine gun | H&K MP7 | HK 4.6x30mm | 30 | 950 (cyclic) | 735 |


+ 60
- 0
tools/audio-interval-test/index.html ファイルの表示

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Audio Interval Test</title>
<style>
label {
position: relative;
}

label > span {
position: absolute;
left: -999999px;
}

label + input[type="checkbox"] {
position: absolute;
left: -999999px;
}
</style>
</head>
<body>
<form id="formAudio">
<fieldset>
<legend>
Repeating Sounds
</legend>
<div>
<label>
<span>Interval (bpm)</span>
<input
type="number"
name="interval"
value="750"
min="100"
max="1000"
/>
</label>
<input
type="checkbox"
name="play"
readonly
tabindex="-1"
checked
/>
</div>
<div>
<label>
<span>Interval (ms)</span>
<output>-</output>
</label>
</div>
<button type="submit">
Toggle Sound
</button>
</fieldset>
</form>
<script src="index.js"></script>
</body>
</html>

+ 57
- 0
tools/audio-interval-test/index.js ファイルの表示

@@ -0,0 +1,57 @@
function AudioForm(el) {
const interval = el.elements['interval']
const play = el.elements['play']
const output = el.querySelector('output')
const audioPool = []
let intervalHandle = null
let audioIndex = 0
const items = 50

for (let i = 0; i < items; i += 1) {
const newAudio = new Audio('./sfx/weapons/guns/smg-hkmp7/1_unload_var0.wav')
newAudio.volume = 0.2;
newAudio.addEventListener('canplaythrough', () => {
audioPool[i].ready = true
})
newAudio.addEventListener('ended', () => {
newAudio.pause()
newAudio.currentTime = 0
})

audioPool[i] = {
audio: newAudio,
ended: true,
ready: false,
}
newAudio.load()
}

const playSound = () => {
for (let i = 0; i < items; i += 1) {
if (!audioPool[i].ready) {
return;
}
}

audioPool[audioIndex].audio.play();
audioIndex = (audioIndex + 1) % items;
}

el.addEventListener('submit', (e) => {
e.preventDefault()

const ms = 60000 / Number(interval.value);
output.innerText = `${ms} ms`
if (play.checked) {
intervalHandle = window.setInterval(() => {
playSound()
}, ms)
} else {
window.clearInterval(intervalHandle);
}

play.checked = !play.checked
})
}

const audioForm = new AudioForm(window.document.getElementById('formAudio'))

+ 1
- 0
tools/audio-interval-test/sfx ファイルの表示

@@ -0,0 +1 @@
../../assets/sfx

+ 180
- 0
tools/websocket-client/index.html ファイルの表示

@@ -0,0 +1,180 @@
<!DOCTYPE HTML>
<html lang="en-PH">
<head>
<meta charset="utf-8">
<title>Websocket Client</title>
<style>
form {
margin: 2em 0;
}

fieldset {
display: contents;
}

legend {
position: absolute;
left: -999999px;
}

legend ~ div {
margin: 0.5em 0;
}

legend ~ div > div {
display: flex;
gap: 0.5em;
}

legend ~ div > div :first-child {
flex: auto;
}

legend ~ div > div :first-child > label {
display: block;
width: 100%;
}

legend ~ div > div :first-child > label > input {
display: block;
width: 100%;
box-sizing: border-box;
}

label {
position: relative;
}

label > span {
position: absolute;
left: -999999px;
}

label + input[type="checkbox"] {
position: absolute;
left: -999999px;
}

textarea {
width: 100%;
box-sizing: border-box;
display: block;
}
</style>
</head>
<body>
<h1>Websocket Client</h1>
<form
id="formConnection"
>
<fieldset>
<legend>Server</legend>
<div>
<div>
<div>
<label>
<span>URL</span>
<input
type="url"
name="serverUrl"
autocomplete="off"
value="ws://localhost:42069"
required
>
</label>
</div>
</div>
</div>
<div>
<div>
<div>
<label>
<span>Username</span>
<input
type="text"
name="username"
autocomplete="off"
value="Web"
required
>
</label>
</div>
</div>
</div>
<button
type="submit"
name="connect"
>
Connect
</button>
</fieldset>
</form>
<form
id="formMessage"
>
<fieldset
name="fieldset"
disabled
>
<legend>Message</legend>
<div>
<div>
<div>
<label>
<span>Message</span>
<input
type="text"
value=""
autocomplete="off"
name="message"
placeholder="Type your message"
>
</label>
<input
type="checkbox"
name="binary"
readonly
tabindex="-1"
/>
</div>
<button
type="submit"
>
Send as Text (Enter)
</button>
<button
name="submitBinary"
type="button"
>
Send as Binary (Shift + Enter)
</button>
</div>
</div>
</fieldset>
</form>
<form
id="formLogs"
>
<fieldset>
<legend>Logs</legend>
<div>
<label>
<span>Logs</span>
<textarea
rows="10"
cols="50"
name="logs"
readonly
></textarea>
</label>
</div>
<button
type="submit"
>
Clear Logs
</button>
</fieldset>
</form>
<script src="index.js"></script>
</body>
</html>

+ 149
- 0
tools/websocket-client/index.js ファイルの表示

@@ -0,0 +1,149 @@
const stringifyData = async value => {
const isString = typeof value === 'string'
const resolve = () => (
isString
? Promise.resolve(value)
: value.arrayBuffer()
)

const a = await resolve()

if (isString) {
return `String:${a.length}(${a})`
}

const bytes = Array.from(new Uint8Array(a)).map(c => Number(c).toString(16).padStart(2, '0')).join(' ')
return `Binary:${a.byteLength}(${bytes})`
}

function ConnectionForm(el) {
let ws = null
el.addEventListener('submit', e => {
e.preventDefault()
if (!ws) {
const username = el.elements['username'].value
const baseUrl = el.elements['serverUrl'].value
ws = new WebSocket(`${baseUrl}?username=${username}`)

ws.addEventListener('open', () => {
this.messageForm.enable()
this.logsForm.append('Connection opened')
el.elements['serverUrl'].setAttribute('disabled', 'disabled')
el.elements['username'].setAttribute('disabled', 'disabled')
el.elements['connect'].innerText = 'Disconnect'
})

ws.addEventListener('message', evt => {
stringifyData(evt.data).then(value => {
this.logsForm.append(`Recv: ${value}`)
})
})

ws.addEventListener('error', evt => {
console.error(evt)
})

ws.addEventListener('close', event => {
this.messageForm.reset()
this.messageForm.disable()
this.logsForm.append(`Connection closed: wasClean: ${event.wasClean}, evCode: ${event.code}`)
el.elements['serverUrl'].removeAttribute('disabled')
el.elements['username'].removeAttribute('disabled')
el.elements['connect'].innerText = 'Connect'
ws = null
})
return
}
ws.close()
})

this.send = value => {
if (!ws) {
return
}
stringifyData(value).then(v => {
this.logsForm.append(`Send: ${v}`)
ws.send(value)
})
}
}

function MessageForm(el) {
const inputMessage = el.elements['message']
const binary = el.elements['binary']

inputMessage.addEventListener('keydown', e => {
if (e.key !== 'Shift') {
return;
}
binary.checked = true;
});

inputMessage.addEventListener('keyup', e => {
if (e.key !== 'Shift') {
return;
}
binary.checked = false;
});

el.addEventListener('submit', e => {
e.preventDefault()

if (inputMessage.value.length < 1) {
return
}


this.connectionForm.send(
binary.checked
? new Blob(inputMessage.value.split(''))
: inputMessage.value,
);
inputMessage.value = ''
inputMessage.focus()
})

el.elements['submitBinary'].addEventListener('click', e => {
e.preventDefault()
if (inputMessage.value.length < 1) {
return
}
this.connectionForm.send(new Blob(inputMessage.value.split('')))
inputMessage.value = ''
inputMessage.focus()
})

this.reset = () => {
inputMessage.value = ''
}

this.enable = () => {
el.elements['fieldset'].removeAttribute('disabled')
}

this.disable = () => {
el.elements['fieldset'].setAttribute('disabled', 'disabled')
}
}

function LogsForm(el) {
let logs = el.elements['logs']

el.addEventListener('submit', e => {
e.preventDefault()
logs.value = ''
})

this.append = data => {
logs.value += data + '\n'
logs.scrollTop = logs.scrollHeight
}
}

const logsForm = new LogsForm(window.document.getElementById('formLogs'))
const messageForm = new MessageForm(window.document.getElementById('formMessage'))
const connectionForm = new ConnectionForm(window.document.getElementById('formConnection'))

connectionForm.logsForm = logsForm
connectionForm.messageForm = messageForm
messageForm.connectionForm = connectionForm

読み込み中…
キャンセル
保存