Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
krypciak committed Apr 14, 2024
1 parent 6313758 commit 6326121
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 35 deletions.
32 changes: 28 additions & 4 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { io, Socket as _Socket } from 'socket.io-client'
import type { ClientToServerEvents, PlayerJoinResponse, ServerSettingsBase, ServerToClientEvents, ToClientUpdatePacket } from 'cc-multibakery/src/api.d.ts'
import { runUpdatePacket } from './update-packet-run'
import { UpdatePacketGather } from './update-packet-gather'
import { injectEntityStateDefinitions } from 'cc-multibakery/src/state/states'

type Socket = _Socket<ServerToClientEvents, ClientToServerEvents>
const TIMEOUT = 5000
Expand All @@ -11,10 +12,21 @@ export class Client {
updatePacketGather: UpdatePacketGather
socket!: Socket

host!: string
port!: number
username!: string

isExecutingUpdatePacketNow: boolean = false

constructor() {
this.updatePacketGather = new UpdatePacketGather()
import('../node_modules/cc-multibakery/src/misc/godmode')
import('./injects')
this.init()
}
private async init() {
await import('../node_modules/cc-multibakery/src/misc/godmode')
await import('../node_modules/cc-multibakery/src/dummy-player')
await import('./injects')
injectEntityStateDefinitions()

const self = this
sc.GameModel.inject({
Expand Down Expand Up @@ -55,6 +67,9 @@ export class Client {
const joinData: PlayerJoinResponse = await this.socket.timeout(TIMEOUT).emitWithAck('join', username)
if (joinData.usernameTaken) throw new Error(`username: ${username} is taken`)
this.serverSettings = joinData.serverSettings
this.host = host
this.port = port
this.username = username

window.addEventListener('beforeunload', () => {
this.socket.close()
Expand All @@ -66,11 +81,20 @@ export class Client {
ig.storage.loadSlot(saveData, false)
ig.interact.entries.forEach(e => ig.interact.removeEntry(e))

if (this.serverSettings.godmode) ig.godmode()

const mapName = joinData.mapName
ig.game.teleport(mapName)

await new Promise<void>(resolve => {
const id = setInterval(() => {
if (ig.game?.maps?.length > 0) {
clearInterval(id)
resolve()
}
}, 30)
})
runUpdatePacket(joinData.state.packet)
if (!ig.game.playerEntity) throw new Error()

this.socket.on('update', (packet: ToClientUpdatePacket) => {
runUpdatePacket(packet)
})
Expand Down
24 changes: 19 additions & 5 deletions src/injects.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { emptyGatherInput } from 'cc-multibakery/src/api'

export {}

sc.CrossCode.inject({
createPlayer() {
if (!ig.client.isConnected()) return this.parent()
const dummy = this.spawnEntity(ig.dummy.DummyPlayer, 0, 0, 0, { username: ig.client.username, ignoreInputForcer: false })
this.playerEntity = dummy
sc.model.player = dummy.model
},
})
ig.Game.inject({
setPaused(paused) {
const orig = this.paused
Expand All @@ -13,9 +19,17 @@ ig.Game.inject({
},
})

ig.ENTITY.Player.inject({
ig.dummy.DummyPlayer.inject({
gatherInput() {
if (!ig.client.isConnected() || !ig.game.pausedVirtual) return this.parent()
return emptyGatherInput()
if (ig.client.isConnected() && this === ig.game.playerEntity && ig.game.pausedVirtual) return emptyGatherInput()
return this.parent()
},
})

ig.Vars.inject({
set(...args) {
if (!ig.client.isConnected() || ig.client.isExecutingUpdatePacketNow) {
this.parent(...args)
}
},
})
2 changes: 2 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default class CCMultiplayerClient implements PluginClass {
}

async prestart() {
await import('../node_modules/cc-multibakery/src/misc/modify-prototypes')
await import('../node_modules/cc-multibakery/src/misc/entity-uuid')
ig.client = new Client()
}

Expand Down
43 changes: 20 additions & 23 deletions src/update-packet-gather.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import type { FromClientUpdatePacket } from 'cc-multibakery/src/api'
import { getDummyUpdateInputFromIgInput, type FromClientUpdatePacket } from 'cc-multibakery/src/api'

export class UpdatePacketGather {
private state: FromClientUpdatePacket = {}
private state!: FromClientUpdatePacket

constructor() {
/* in prestart */
this.pop()
this.reset()

const self = this
sc.PlayerModel.inject({
setElementMode(element, force, skipEffect) {
const ret = this.parent(element, force, skipEffect)
if (ig.client.isConnected() && this === sc.model.player) {
if (!ig.client.isConnected()) return this.parent(element, force, skipEffect)

if (ig.client.isExecutingUpdatePacketNow || this !== sc.model.player) {
return this.parent(element, force, skipEffect)
} else if (this === sc.model.player) {
self.state.element = element
}
return ret
return false
},
})
}
Expand All @@ -23,25 +26,13 @@ export class UpdatePacketGather {
if (!ig?.input) return
if (this.state.paused) throw new Error()

this.state.input = {
isUsingMouse: ig.input.isUsingMouse,
isUsingKeyboard: ig.input.isUsingKeyboard,
isUsingAccelerometer: ig.input.isUsingAccelerometer,
ignoreKeyboard: ig.input.ignoreKeyboard,
mouseGuiActive: ig.input.mouseGuiActive,
mouse: ig.input.mouse,
accel: ig.input.accel,
presses: ig.input.presses,
keyups: ig.input.keyups,
locks: ig.input.locks,
delayedKeyup: ig.input.delayedKeyup,
currentDevice: ig.input.currentDevice,
actions: ig.input.actions,
}
this.state.input = getDummyUpdateInputFromIgInput(ig.input)
}
private gatherInput() {
if (this.state.paused) throw new Error()
this.state.gatherInput = ig.game?.playerEntity?.gatherInput()
if (!ig.game?.playerEntity) return

this.state.gatherInput = ig.ENTITY.Player.prototype.gatherInput.bind(ig.game.playerEntity)()
}
private relativeCursorPos() {
if (this.state.paused) throw new Error()
Expand All @@ -50,6 +41,12 @@ export class UpdatePacketGather {
ig.system?.getMapFromScreenPos(this.state.relativeCursorPos, sc.control.getMouseX(), sc.control.getMouseY())
}

private reset() {
this.state = {
type: 'ig.dummy.DummyPlayer',
}
}

pop(): FromClientUpdatePacket {
if (!ig.game?.pausedVirtual && !ig.loading && ig.ready && sc.model.isGame()) {
this.relativeCursorPos()
Expand All @@ -59,7 +56,7 @@ export class UpdatePacketGather {
this.state.paused = true
}
const state = this.state
this.state = {}
this.reset()
return state
}
}
46 changes: 43 additions & 3 deletions src/update-packet-run.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,54 @@
import type { ToClientUpdatePacket } from 'cc-multibakery/src/api'
import { EntityStateEntry } from 'cc-multibakery/src/state/states'

export function runUpdatePacket(packet: ToClientUpdatePacket) {
ig.client.isExecutingUpdatePacketNow = true
if (packet.vars) {
for (const { path, value } of packet.vars) {
ig.vars.set(path, value)
}
}
if (packet.pos && ig.game.playerEntity) {
if (!Vec3.equal(ig.game.playerEntity.coll.pos, packet.pos)) {
ig.game.playerEntity.setPos(packet.pos.x, packet.pos.y, packet.pos.z)

if (packet.entityStates && ig.game?.maps?.length > 0 /* check if the game has loaded already */) {
for (const uuid in packet.entityStates) {
const state = packet.entityStates[uuid]

if (state.type == 'ig.dummy.DummyPlayer') {
setPlayerState(state, uuid)
} else throw new Error(`Entity uuid: ${uuid} type: ${state.type} is not implemeneted`)
}
}
if (packet.playersLeft) {
console.log(packet.playersLeft)
for (const uuid of packet.playersLeft) {
const player = ig.game.entitiesByUUID[uuid]
if (!player) throw new Error('tried to "leave" a non exisitng player')
if (player.type !== 'ig.dummy.DummyPlayer') throw new Error('tried to "leave" a non player')
player.kill()
delete ig.game.entitiesByUUID[player.uuid]
}
}
ig.client.isExecutingUpdatePacketNow = false
}
function setPlayerState(state: EntityStateEntry<'ig.dummy.DummyPlayer'>, uuid: string) {
let dummy = ig.game.entitiesByUUID[uuid] as ig.dummy.DummyPlayer | undefined
if (dummy?._killed) dummy = undefined

if (state.username == ig.client.username && !dummy) {
if (!(ig.game.playerEntity instanceof ig.dummy.DummyPlayer)) throw new Error('not possible')
dummy = ig.game.playerEntity
delete ig.game.entitiesByUUID[dummy.uuid]
dummy.uuid = uuid
ig.game.entitiesByUUID[uuid] = dummy
if (ig.client.serverSettings!.godmode) ig.godmode(dummy.model)
} else if (!dummy) {
dummy = ig.game.spawnEntity(ig.dummy.DummyPlayer, 0, 0, 0, { username: state.username!, uuid })
console.log('creating ', state.username, ig.loading, ig.ready)
ig.game.entitiesByUUID[uuid] = dummy
if (ig.client.serverSettings!.godmode) ig.godmode(dummy.model)
dummy.showUsernameBox()
console.log('created ')
}

dummy.setState(state)
}

0 comments on commit 6326121

Please sign in to comment.