Drafted use of dynamics in jsexport.

This commit is contained in:
genxium 2022-12-23 22:31:55 +08:00
parent 9d03794e49
commit df5c9fda30
10 changed files with 752 additions and 210681 deletions

View File

@ -44,50 +44,15 @@ const (
MAGIC_JOIN_INDEX_INVALID = -1 MAGIC_JOIN_INDEX_INVALID = -1
) )
const (
COLLISION_CATEGORY_CONTROLLED_PLAYER = (1 << 1)
COLLISION_CATEGORY_BARRIER = (1 << 2)
COLLISION_MASK_FOR_CONTROLLED_PLAYER = (COLLISION_CATEGORY_BARRIER)
COLLISION_MASK_FOR_BARRIER = (COLLISION_CATEGORY_CONTROLLED_PLAYER)
COLLISION_PLAYER_INDEX_PREFIX = (1 << 17)
COLLISION_BARRIER_INDEX_PREFIX = (1 << 16)
COLLISION_BULLET_INDEX_PREFIX = (1 << 15)
)
const ( const (
MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED = -1 MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED = -1
MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED = -2 MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED = -2
) )
const (
ATK_CHARACTER_STATE_IDLE1 = int32(0)
ATK_CHARACTER_STATE_WALKING = int32(1)
ATK_CHARACTER_STATE_ATK1 = int32(2)
ATK_CHARACTER_STATE_ATKED1 = int32(3)
ATK_CHARACTER_STATE_INAIR_IDLE1 = int32(4)
ATK_CHARACTER_STATE_INAIR_ATK1 = int32(5)
ATK_CHARACTER_STATE_INAIR_ATKED1 = int32(6)
)
const ( const (
DEFAULT_PLAYER_RADIUS = float64(12) DEFAULT_PLAYER_RADIUS = float64(12)
) )
// These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged.
var DIRECTION_DECODER = [][]int32{
{0, 0},
{0, +2},
{0, -2},
{+2, 0},
{-2, 0},
{+1, +1},
{-1, -1},
{+1, -1},
{-1, +1},
}
type RoomBattleState struct { type RoomBattleState struct {
IDLE int32 IDLE int32
WAITING int32 WAITING int32

View File

@ -79,6 +79,10 @@ message InputsBufferSnapshot {
bool shouldForceResync = 4; bool shouldForceResync = 4;
} }
message Barrier {
sharedprotos.Polygon2D boundary = 1;
}
message MeleeBullet { message MeleeBullet {
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/ // Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
// ALL lengths are in world coordinate // ALL lengths are in world coordinate
@ -148,9 +152,11 @@ message BattleColliderInfo {
message RoomDownsyncFrame { message RoomDownsyncFrame {
int32 id = 1; int32 id = 1;
map<int32, PlayerDownsync> players = 2; repeated PlayerDownsync playersArr = 2;
int64 countdownNanos = 3; int64 countdownNanos = 3;
repeated MeleeBullet meleeBullets = 4; // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise repeated MeleeBullet meleeBullets = 4; // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise
uint64 backendUnconfirmedMask = 5; // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync uint64 backendUnconfirmedMask = 5; // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync
bool shouldForceResync = 6; bool shouldForceResync = 6;
map<int32, PlayerDownsync> players = 99; // TO BE DEPRECATED
} }

View File

@ -3954,6 +3954,214 @@ $root.protos = (function() {
return InputsBufferSnapshot; return InputsBufferSnapshot;
})(); })();
protos.Barrier = (function() {
/**
* Properties of a Barrier.
* @memberof protos
* @interface IBarrier
* @property {sharedprotos.Polygon2D|null} [boundary] Barrier boundary
*/
/**
* Constructs a new Barrier.
* @memberof protos
* @classdesc Represents a Barrier.
* @implements IBarrier
* @constructor
* @param {protos.IBarrier=} [properties] Properties to set
*/
function Barrier(properties) {
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* Barrier boundary.
* @member {sharedprotos.Polygon2D|null|undefined} boundary
* @memberof protos.Barrier
* @instance
*/
Barrier.prototype.boundary = null;
/**
* Creates a new Barrier instance using the specified properties.
* @function create
* @memberof protos.Barrier
* @static
* @param {protos.IBarrier=} [properties] Properties to set
* @returns {protos.Barrier} Barrier instance
*/
Barrier.create = function create(properties) {
return new Barrier(properties);
};
/**
* Encodes the specified Barrier message. Does not implicitly {@link protos.Barrier.verify|verify} messages.
* @function encode
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Barrier.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.boundary != null && Object.hasOwnProperty.call(message, "boundary"))
$root.sharedprotos.Polygon2D.encode(message.boundary, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
return writer;
};
/**
* Encodes the specified Barrier message, length delimited. Does not implicitly {@link protos.Barrier.verify|verify} messages.
* @function encodeDelimited
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Barrier.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a Barrier message from the specified reader or buffer.
* @function decode
* @memberof protos.Barrier
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {protos.Barrier} Barrier
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Barrier.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.protos.Barrier();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.boundary = $root.sharedprotos.Polygon2D.decode(reader, reader.uint32());
break;
}
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a Barrier message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof protos.Barrier
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {protos.Barrier} Barrier
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Barrier.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a Barrier message.
* @function verify
* @memberof protos.Barrier
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
Barrier.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.boundary != null && message.hasOwnProperty("boundary")) {
var error = $root.sharedprotos.Polygon2D.verify(message.boundary);
if (error)
return "boundary." + error;
}
return null;
};
/**
* Creates a Barrier message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof protos.Barrier
* @static
* @param {Object.<string,*>} object Plain object
* @returns {protos.Barrier} Barrier
*/
Barrier.fromObject = function fromObject(object) {
if (object instanceof $root.protos.Barrier)
return object;
var message = new $root.protos.Barrier();
if (object.boundary != null) {
if (typeof object.boundary !== "object")
throw TypeError(".protos.Barrier.boundary: object expected");
message.boundary = $root.sharedprotos.Polygon2D.fromObject(object.boundary);
}
return message;
};
/**
* Creates a plain object from a Barrier message. Also converts values to other types if specified.
* @function toObject
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Barrier.toObject = function toObject(message, options) {
if (!options)
options = {};
var object = {};
if (options.defaults)
object.boundary = null;
if (message.boundary != null && message.hasOwnProperty("boundary"))
object.boundary = $root.sharedprotos.Polygon2D.toObject(message.boundary, options);
return object;
};
/**
* Converts this Barrier to JSON.
* @function toJSON
* @memberof protos.Barrier
* @instance
* @returns {Object.<string,*>} JSON object
*/
Barrier.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for Barrier
* @function getTypeUrl
* @memberof protos.Barrier
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
Barrier.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/protos.Barrier";
};
return Barrier;
})();
protos.MeleeBullet = (function() { protos.MeleeBullet = (function() {
/** /**
@ -5595,11 +5803,12 @@ $root.protos = (function() {
* @memberof protos * @memberof protos
* @interface IRoomDownsyncFrame * @interface IRoomDownsyncFrame
* @property {number|null} [id] RoomDownsyncFrame id * @property {number|null} [id] RoomDownsyncFrame id
* @property {Object.<string,protos.PlayerDownsync>|null} [players] RoomDownsyncFrame players * @property {Array.<protos.PlayerDownsync>|null} [playersArr] RoomDownsyncFrame playersArr
* @property {number|Long|null} [countdownNanos] RoomDownsyncFrame countdownNanos * @property {number|Long|null} [countdownNanos] RoomDownsyncFrame countdownNanos
* @property {Array.<protos.MeleeBullet>|null} [meleeBullets] RoomDownsyncFrame meleeBullets * @property {Array.<protos.MeleeBullet>|null} [meleeBullets] RoomDownsyncFrame meleeBullets
* @property {number|Long|null} [backendUnconfirmedMask] RoomDownsyncFrame backendUnconfirmedMask * @property {number|Long|null} [backendUnconfirmedMask] RoomDownsyncFrame backendUnconfirmedMask
* @property {boolean|null} [shouldForceResync] RoomDownsyncFrame shouldForceResync * @property {boolean|null} [shouldForceResync] RoomDownsyncFrame shouldForceResync
* @property {Object.<string,protos.PlayerDownsync>|null} [players] RoomDownsyncFrame players
*/ */
/** /**
@ -5611,8 +5820,9 @@ $root.protos = (function() {
* @param {protos.IRoomDownsyncFrame=} [properties] Properties to set * @param {protos.IRoomDownsyncFrame=} [properties] Properties to set
*/ */
function RoomDownsyncFrame(properties) { function RoomDownsyncFrame(properties) {
this.players = {}; this.playersArr = [];
this.meleeBullets = []; this.meleeBullets = [];
this.players = {};
if (properties) if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) if (properties[keys[i]] != null)
@ -5628,12 +5838,12 @@ $root.protos = (function() {
RoomDownsyncFrame.prototype.id = 0; RoomDownsyncFrame.prototype.id = 0;
/** /**
* RoomDownsyncFrame players. * RoomDownsyncFrame playersArr.
* @member {Object.<string,protos.PlayerDownsync>} players * @member {Array.<protos.PlayerDownsync>} playersArr
* @memberof protos.RoomDownsyncFrame * @memberof protos.RoomDownsyncFrame
* @instance * @instance
*/ */
RoomDownsyncFrame.prototype.players = $util.emptyObject; RoomDownsyncFrame.prototype.playersArr = $util.emptyArray;
/** /**
* RoomDownsyncFrame countdownNanos. * RoomDownsyncFrame countdownNanos.
@ -5667,6 +5877,14 @@ $root.protos = (function() {
*/ */
RoomDownsyncFrame.prototype.shouldForceResync = false; RoomDownsyncFrame.prototype.shouldForceResync = false;
/**
* RoomDownsyncFrame players.
* @member {Object.<string,protos.PlayerDownsync>} players
* @memberof protos.RoomDownsyncFrame
* @instance
*/
RoomDownsyncFrame.prototype.players = $util.emptyObject;
/** /**
* Creates a new RoomDownsyncFrame instance using the specified properties. * Creates a new RoomDownsyncFrame instance using the specified properties.
* @function create * @function create
@ -5693,11 +5911,9 @@ $root.protos = (function() {
writer = $Writer.create(); writer = $Writer.create();
if (message.id != null && Object.hasOwnProperty.call(message, "id")) if (message.id != null && Object.hasOwnProperty.call(message, "id"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.id); writer.uint32(/* id 1, wireType 0 =*/8).int32(message.id);
if (message.players != null && Object.hasOwnProperty.call(message, "players")) if (message.playersArr != null && message.playersArr.length)
for (var keys = Object.keys(message.players), i = 0; i < keys.length; ++i) { for (var i = 0; i < message.playersArr.length; ++i)
writer.uint32(/* id 2, wireType 2 =*/18).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]); $root.protos.PlayerDownsync.encode(message.playersArr[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
$root.protos.PlayerDownsync.encode(message.players[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
if (message.countdownNanos != null && Object.hasOwnProperty.call(message, "countdownNanos")) if (message.countdownNanos != null && Object.hasOwnProperty.call(message, "countdownNanos"))
writer.uint32(/* id 3, wireType 0 =*/24).int64(message.countdownNanos); writer.uint32(/* id 3, wireType 0 =*/24).int64(message.countdownNanos);
if (message.meleeBullets != null && message.meleeBullets.length) if (message.meleeBullets != null && message.meleeBullets.length)
@ -5707,6 +5923,11 @@ $root.protos = (function() {
writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.backendUnconfirmedMask); writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.backendUnconfirmedMask);
if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync")) if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync"))
writer.uint32(/* id 6, wireType 0 =*/48).bool(message.shouldForceResync); writer.uint32(/* id 6, wireType 0 =*/48).bool(message.shouldForceResync);
if (message.players != null && Object.hasOwnProperty.call(message, "players"))
for (var keys = Object.keys(message.players), i = 0; i < keys.length; ++i) {
writer.uint32(/* id 99, wireType 2 =*/794).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]);
$root.protos.PlayerDownsync.encode(message.players[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
return writer; return writer;
}; };
@ -5746,6 +5967,30 @@ $root.protos = (function() {
break; break;
} }
case 2: { case 2: {
if (!(message.playersArr && message.playersArr.length))
message.playersArr = [];
message.playersArr.push($root.protos.PlayerDownsync.decode(reader, reader.uint32()));
break;
}
case 3: {
message.countdownNanos = reader.int64();
break;
}
case 4: {
if (!(message.meleeBullets && message.meleeBullets.length))
message.meleeBullets = [];
message.meleeBullets.push($root.protos.MeleeBullet.decode(reader, reader.uint32()));
break;
}
case 5: {
message.backendUnconfirmedMask = reader.uint64();
break;
}
case 6: {
message.shouldForceResync = reader.bool();
break;
}
case 99: {
if (message.players === $util.emptyObject) if (message.players === $util.emptyObject)
message.players = {}; message.players = {};
var end2 = reader.uint32() + reader.pos; var end2 = reader.uint32() + reader.pos;
@ -5768,24 +6013,6 @@ $root.protos = (function() {
message.players[key] = value; message.players[key] = value;
break; break;
} }
case 3: {
message.countdownNanos = reader.int64();
break;
}
case 4: {
if (!(message.meleeBullets && message.meleeBullets.length))
message.meleeBullets = [];
message.meleeBullets.push($root.protos.MeleeBullet.decode(reader, reader.uint32()));
break;
}
case 5: {
message.backendUnconfirmedMask = reader.uint64();
break;
}
case 6: {
message.shouldForceResync = reader.bool();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -5824,18 +6051,13 @@ $root.protos = (function() {
if (message.id != null && message.hasOwnProperty("id")) if (message.id != null && message.hasOwnProperty("id"))
if (!$util.isInteger(message.id)) if (!$util.isInteger(message.id))
return "id: integer expected"; return "id: integer expected";
if (message.players != null && message.hasOwnProperty("players")) { if (message.playersArr != null && message.hasOwnProperty("playersArr")) {
if (!$util.isObject(message.players)) if (!Array.isArray(message.playersArr))
return "players: object expected"; return "playersArr: array expected";
var key = Object.keys(message.players); for (var i = 0; i < message.playersArr.length; ++i) {
for (var i = 0; i < key.length; ++i) { var error = $root.protos.PlayerDownsync.verify(message.playersArr[i]);
if (!$util.key32Re.test(key[i]))
return "players: integer key{k:int32} expected";
{
var error = $root.protos.PlayerDownsync.verify(message.players[key[i]]);
if (error) if (error)
return "players." + error; return "playersArr." + error;
}
} }
} }
if (message.countdownNanos != null && message.hasOwnProperty("countdownNanos")) if (message.countdownNanos != null && message.hasOwnProperty("countdownNanos"))
@ -5856,6 +6078,20 @@ $root.protos = (function() {
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
if (typeof message.shouldForceResync !== "boolean") if (typeof message.shouldForceResync !== "boolean")
return "shouldForceResync: boolean expected"; return "shouldForceResync: boolean expected";
if (message.players != null && message.hasOwnProperty("players")) {
if (!$util.isObject(message.players))
return "players: object expected";
var key = Object.keys(message.players);
for (var i = 0; i < key.length; ++i) {
if (!$util.key32Re.test(key[i]))
return "players: integer key{k:int32} expected";
{
var error = $root.protos.PlayerDownsync.verify(message.players[key[i]]);
if (error)
return "players." + error;
}
}
}
return null; return null;
}; };
@ -5873,14 +6109,14 @@ $root.protos = (function() {
var message = new $root.protos.RoomDownsyncFrame(); var message = new $root.protos.RoomDownsyncFrame();
if (object.id != null) if (object.id != null)
message.id = object.id | 0; message.id = object.id | 0;
if (object.players) { if (object.playersArr) {
if (typeof object.players !== "object") if (!Array.isArray(object.playersArr))
throw TypeError(".protos.RoomDownsyncFrame.players: object expected"); throw TypeError(".protos.RoomDownsyncFrame.playersArr: array expected");
message.players = {}; message.playersArr = [];
for (var keys = Object.keys(object.players), i = 0; i < keys.length; ++i) { for (var i = 0; i < object.playersArr.length; ++i) {
if (typeof object.players[keys[i]] !== "object") if (typeof object.playersArr[i] !== "object")
throw TypeError(".protos.RoomDownsyncFrame.players: object expected"); throw TypeError(".protos.RoomDownsyncFrame.playersArr: object expected");
message.players[keys[i]] = $root.protos.PlayerDownsync.fromObject(object.players[keys[i]]); message.playersArr[i] = $root.protos.PlayerDownsync.fromObject(object.playersArr[i]);
} }
} }
if (object.countdownNanos != null) if (object.countdownNanos != null)
@ -5913,6 +6149,16 @@ $root.protos = (function() {
message.backendUnconfirmedMask = new $util.LongBits(object.backendUnconfirmedMask.low >>> 0, object.backendUnconfirmedMask.high >>> 0).toNumber(true); message.backendUnconfirmedMask = new $util.LongBits(object.backendUnconfirmedMask.low >>> 0, object.backendUnconfirmedMask.high >>> 0).toNumber(true);
if (object.shouldForceResync != null) if (object.shouldForceResync != null)
message.shouldForceResync = Boolean(object.shouldForceResync); message.shouldForceResync = Boolean(object.shouldForceResync);
if (object.players) {
if (typeof object.players !== "object")
throw TypeError(".protos.RoomDownsyncFrame.players: object expected");
message.players = {};
for (var keys = Object.keys(object.players), i = 0; i < keys.length; ++i) {
if (typeof object.players[keys[i]] !== "object")
throw TypeError(".protos.RoomDownsyncFrame.players: object expected");
message.players[keys[i]] = $root.protos.PlayerDownsync.fromObject(object.players[keys[i]]);
}
}
return message; return message;
}; };
@ -5929,8 +6175,10 @@ $root.protos = (function() {
if (!options) if (!options)
options = {}; options = {};
var object = {}; var object = {};
if (options.arrays || options.defaults) if (options.arrays || options.defaults) {
object.playersArr = [];
object.meleeBullets = []; object.meleeBullets = [];
}
if (options.objects || options.defaults) if (options.objects || options.defaults)
object.players = {}; object.players = {};
if (options.defaults) { if (options.defaults) {
@ -5949,11 +6197,10 @@ $root.protos = (function() {
} }
if (message.id != null && message.hasOwnProperty("id")) if (message.id != null && message.hasOwnProperty("id"))
object.id = message.id; object.id = message.id;
var keys2; if (message.playersArr && message.playersArr.length) {
if (message.players && (keys2 = Object.keys(message.players)).length) { object.playersArr = [];
object.players = {}; for (var j = 0; j < message.playersArr.length; ++j)
for (var j = 0; j < keys2.length; ++j) object.playersArr[j] = $root.protos.PlayerDownsync.toObject(message.playersArr[j], options);
object.players[keys2[j]] = $root.protos.PlayerDownsync.toObject(message.players[keys2[j]], options);
} }
if (message.countdownNanos != null && message.hasOwnProperty("countdownNanos")) if (message.countdownNanos != null && message.hasOwnProperty("countdownNanos"))
if (typeof message.countdownNanos === "number") if (typeof message.countdownNanos === "number")
@ -5972,6 +6219,12 @@ $root.protos = (function() {
object.backendUnconfirmedMask = options.longs === String ? $util.Long.prototype.toString.call(message.backendUnconfirmedMask) : options.longs === Number ? new $util.LongBits(message.backendUnconfirmedMask.low >>> 0, message.backendUnconfirmedMask.high >>> 0).toNumber(true) : message.backendUnconfirmedMask; object.backendUnconfirmedMask = options.longs === String ? $util.Long.prototype.toString.call(message.backendUnconfirmedMask) : options.longs === Number ? new $util.LongBits(message.backendUnconfirmedMask.low >>> 0, message.backendUnconfirmedMask.high >>> 0).toNumber(true) : message.backendUnconfirmedMask;
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
object.shouldForceResync = message.shouldForceResync; object.shouldForceResync = message.shouldForceResync;
var keys2;
if (message.players && (keys2 = Object.keys(message.players)).length) {
object.players = {};
for (var j = 0; j < keys2.length; ++j)
object.players[keys2[j]] = $root.protos.PlayerDownsync.toObject(message.players[keys2[j]], options);
}
return object; return object;
}; };

2
jsexport/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
jsexport.js
jsexport.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,71 +3,13 @@ package main
import ( import (
"github.com/gopherjs/gopherjs/js" "github.com/gopherjs/gopherjs/js"
"github.com/solarlune/resolv" "github.com/solarlune/resolv"
"dnmshared"
. "dnmshared/sharedprotos"
. "jsexport/protos" . "jsexport/protos"
. "jsexport/models" "jsexport/models"
. "dnmshared"
) )
var DIRECTION_DECODER = [][]int32{
{0, 0},
{0, +2},
{0, -2},
{+2, 0},
{-2, 0},
{+1, +1},
{-1, -1},
{+1, -1},
{-1, +1},
}
func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputScaleFrames int32) int32 {
if renderFrameId < inputDelayFrames {
return 0
}
return ((renderFrameId - inputDelayFrames) >> inputScaleFrames)
}
func DecodeInput(encodedInput uint64) *InputFrameDecoded {
encodedDirection := (encodedInput & uint64(15))
btnALevel := int32((encodedInput >> 4) & 1)
btnBLevel := int32((encodedInput >> 5) & 1)
return &InputFrameDecoded{
Dx: DIRECTION_DECODER[encodedDirection][0],
Dy: DIRECTION_DECODER[encodedDirection][1],
BtnALevel: btnALevel,
BtnBLevel: btnBLevel,
}
}
func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
collision := playerCollider.Check(0, 0)
if nil == collision {
return ret
}
for _, obj := range collision.Objects {
switch obj.Data.(type) {
case *Barrier:
barrierShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := dnmshared.CalcPushbacks(0, 0, playerShape, barrierShape)
if !overlapped {
continue
}
// ALWAY snap into hardPushbacks!
// [OverlapX, OverlapY] is the unit vector that points into the platform
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
pEffPushback.X += pushbackX
pEffPushback.Y += pushbackY
default:
}
}
return ret
}
func NewRingBufferJs(n int32) *js.Object { func NewRingBufferJs(n int32) *js.Object {
return js.MakeWrapper(dnmshared.NewRingBuffer(n)); return js.MakeWrapper(NewRingBuffer(n));
} }
func NewCollisionSpaceJs(spaceW, spaceH, minStepW, minStepH int) *js.Object { func NewCollisionSpaceJs(spaceW, spaceH, minStepW, minStepH int) *js.Object {
@ -84,7 +26,7 @@ func GenerateRectColliderJs(wx, wy, w, h, topPadding, bottomPadding, leftPadding
``` ```
The "space" variable doesn't need access to the field of "a" in JavaScript level to run "space.Add(...)" method, which is good. The "space" variable doesn't need access to the field of "a" in JavaScript level to run "space.Add(...)" method, which is good.
*/ */
return js.MakeWrapper(dnmshared.GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, tag)); return js.MakeWrapper(GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, tag));
} }
@ -94,216 +36,10 @@ func CheckCollisionJs(obj *resolv.Object, dx, dy float64) *js.Object {
return js.MakeFullWrapper(obj.Check(dx, dy)); return js.MakeFullWrapper(obj.Check(dx, dy));
} }
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *js.Object {
/* // We need access to all fields of RoomDownsyncFrame for displaying in frontend
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object, topPadding, bottomPadding, leftPadding, rightPadding float64, roomCapacity int, jumpingInitVelY int32, playersArr []*Player, inputDelayFrames int32, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY int32, snapIntoPlatformOverlap, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame { return js.MakeFullWrapper(models.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames, inputsBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio))
// [WARNING] This function MUST BE called while "InputsBufferLock" is locked!
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, roomCapacity)
// Make a copy first
for playerId, currPlayerDownsync := range currRenderFrame.Players {
nextRenderFramePlayers[playerId] = &PlayerDownsync{
Id: playerId,
VirtualGridX: currPlayerDownsync.VirtualGridX,
VirtualGridY: currPlayerDownsync.VirtualGridY,
DirX: currPlayerDownsync.DirX,
DirY: currPlayerDownsync.DirY,
VelX: currPlayerDownsync.VelX,
VelY: currPlayerDownsync.VelY,
CharacterState: currPlayerDownsync.CharacterState,
InAir: true,
Speed: currPlayerDownsync.Speed,
BattleState: currPlayerDownsync.BattleState,
Score: currPlayerDownsync.Score,
Removed: currPlayerDownsync.Removed,
JoinIndex: currPlayerDownsync.JoinIndex,
FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
Hp: currPlayerDownsync.Hp,
MaxHp: currPlayerDownsync.MaxHp,
}
if nextRenderFramePlayers[playerId].FramesToRecover < 0 {
nextRenderFramePlayers[playerId].FramesToRecover = 0
}
}
nextRenderFrameMeleeBullets := make([]*MeleeBullet, 0, len(currRenderFrame.MeleeBullets)) // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
effPushbacks := make([]Vec2D, roomCapacity)
hardPushbackNorms := make([][]Vec2D, roomCapacity)
// 1. Process player inputs
if nil != delayedInputFrame {
var delayedInputFrameForPrevRenderFrame *InputFrameDownsync = nil
tmp := inputsBuffer.GetByFrameId(ConvertToInputFrameId(currRenderFrame.Id-1, inputDelayFrames, inputScaleFrames))
if nil != tmp {
delayedInputFrameForPrevRenderFrame = tmp.(*InputFrameDownsync)
}
inputList := delayedInputFrame.InputList
for _, player := range playersArr {
playerId := player.Id
joinIndex := player.JoinIndex
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
if 0 < thatPlayerInNextFrame.FramesToRecover {
continue
}
decodedInput := DecodeInput(inputList[joinIndex-1])
prevBtnALevel, prevBtnBLevel := int32(0), int32(0)
if nil != delayedInputFrameForPrevRenderFrame {
prevDecodedInput := DecodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1])
prevBtnALevel = prevDecodedInput.BtnALevel
prevBtnBLevel = prevDecodedInput.BtnBLevel
}
if decodedInput.BtnBLevel > prevBtnBLevel {
characStateAlreadyInAir := false
if ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATK1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATKED1 == thatPlayerInNextFrame.CharacterState {
characStateAlreadyInAir = true
}
characStateIsInterruptWaivable := false
if ATK_CHARACTER_STATE_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_WALKING == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState {
characStateIsInterruptWaivable = true
}
if !characStateAlreadyInAir && characStateIsInterruptWaivable {
thatPlayerInNextFrame.VelY = jumpingInitVelY
}
}
// Note that by now "0 == thatPlayerInNextFrame.FramesToRecover", we should change "CharacterState" to "WALKING" or "IDLE" depending on player inputs
if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
thatPlayerInNextFrame.DirX = decodedInput.Dx
thatPlayerInNextFrame.DirY = decodedInput.Dy
thatPlayerInNextFrame.VelX = decodedInput.Dx * currPlayerDownsync.Speed
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
}
}
}
// 2. Process player movement
for _, player := range playersArr {
playerId := player.Id
joinIndex := player.JoinIndex
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
// Reset playerCollider position from the "virtual grid position"
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
if thatPlayerInNextFrame.VelY == jumpingInitVelY {
newVy += thatPlayerInNextFrame.VelY
}
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, virtualGridToWorldRatio)
// Update in the collision system
playerCollider.Update()
if currPlayerDownsync.InAir {
thatPlayerInNextFrame.VelX += gravityX
thatPlayerInNextFrame.VelY += gravityY
}
}
// 3. Invoke collision system stepping (no-op for backend collision lib)
// 4. Calc pushbacks for each player (after its movement) w/o bullets
for _, player := range playersArr {
joinIndex := player.JoinIndex
playerId := player.Id
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
hardPushbackNorms[joinIndex-1] = CalcHardPushbacksNorms(playerCollider, playerShape, snapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
fallStopping := false
possiblyFallStoppedOnAnotherPlayer := false
if collision := playerCollider.Check(0, 0); nil != collision {
for _, obj := range collision.Objects {
isBarrier, isAnotherPlayer, isBullet := false, false, false
switch obj.Data.(type) {
case *Barrier:
isBarrier = true
case *Player:
isAnotherPlayer = true
case *MeleeBullet:
isBullet = true
}
if isBullet {
// ignore bullets for this step
continue
}
bShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := dnmshared.CalcPushbacks(0, 0, playerShape, bShape)
if !overlapped {
continue
}
normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
landedOnGravityPushback := (snapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
if landedOnGravityPushback {
// kindly note that one player might land on top of another player, and snapping is also required in such case
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
thatPlayerInNextFrame.InAir = false
}
if isAnotherPlayer {
// [WARNING] The "zero overlap collision" might be randomly detected/missed on either frontend or backend, to have deterministic result we added paddings to all sides of a playerCollider. As each velocity component of (velX, velY) being a multiple of 0.5 at any renderFrame, each position component of (x, y) can only be a multiple of 0.5 too, thus whenever a 1-dimensional collision happens between players from [player#1: i*0.5, player#2: j*0.5, not collided yet] to [player#1: (i+k)*0.5, player#2: j*0.5, collided], the overlap becomes (i+k-j)*0.5+2*s, and after snapping subtraction the effPushback magnitude for each player is (i+k-j)*0.5, resulting in 0.5-multiples-position for the next renderFrame.
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapY
}
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
effPushbacks[joinIndex-1].X += pushbackX
effPushbacks[joinIndex-1].Y += pushbackY
if currPlayerDownsync.InAir && landedOnGravityPushback {
fallStopping = true
if isAnotherPlayer {
possiblyFallStoppedOnAnotherPlayer = true
}
}
}
}
if fallStopping {
thatPlayerInNextFrame.VelX = 0
thatPlayerInNextFrame.VelY = 0
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.FramesToRecover = 0
}
if currPlayerDownsync.InAir {
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
switch oldNextCharacterState {
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
case ATK_CHARACTER_STATE_ATK1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
case ATK_CHARACTER_STATE_ATKED1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
}
}
}
// 7. Get players out of stuck barriers if there's any
for _, player := range playersArr {
joinIndex := player.JoinIndex
playerId := player.Id
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
// Update "virtual grid position"
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, worldToVirtualGridRatio)
}
return &RoomDownsyncFrame{
Id: currRenderFrame.Id + 1,
Players: nextRenderFramePlayers,
MeleeBullets: nextRenderFrameMeleeBullets,
CountdownNanos: (BattleDurationNanos - int64(currRenderFrame.Id)*RollbackEstimatedDtNanos),
}
} }
*/
func main() { func main() {
js.Global.Set("gopkgs", map[string]interface{}{ js.Global.Set("gopkgs", map[string]interface{}{

View File

@ -1,9 +0,0 @@
package models
import (
. "dnmshared/sharedprotos"
)
type Barrier struct {
Boundary *Polygon2D
}

280
jsexport/models/battle.go Normal file
View File

@ -0,0 +1,280 @@
package models
import (
"github.com/solarlune/resolv"
. "dnmshared/sharedprotos"
. "jsexport/protos"
. "dnmshared"
)
const (
COLLISION_PLAYER_INDEX_PREFIX = (1 << 17)
COLLISION_BARRIER_INDEX_PREFIX = (1 << 16)
COLLISION_BULLET_INDEX_PREFIX = (1 << 15)
)
// These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged.
var DIRECTION_DECODER = [][]int32{
{0, 0},
{0, +2},
{0, -2},
{+2, 0},
{-2, 0},
{+1, +1},
{-1, -1},
{+1, -1},
{-1, +1},
}
const (
ATK_CHARACTER_STATE_IDLE1 = int32(0)
ATK_CHARACTER_STATE_WALKING = int32(1)
ATK_CHARACTER_STATE_ATK1 = int32(2)
ATK_CHARACTER_STATE_ATKED1 = int32(3)
ATK_CHARACTER_STATE_INAIR_IDLE1 = int32(4)
ATK_CHARACTER_STATE_INAIR_ATK1 = int32(5)
ATK_CHARACTER_STATE_INAIR_ATKED1 = int32(6)
)
func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputScaleFrames int32) int32 {
if renderFrameId < inputDelayFrames {
return 0
}
return ((renderFrameId - inputDelayFrames) >> inputScaleFrames)
}
func DecodeInput(encodedInput uint64) *InputFrameDecoded {
encodedDirection := (encodedInput & uint64(15))
btnALevel := int32((encodedInput >> 4) & 1)
btnBLevel := int32((encodedInput >> 5) & 1)
return &InputFrameDecoded{
Dx: DIRECTION_DECODER[encodedDirection][0],
Dy: DIRECTION_DECODER[encodedDirection][1],
BtnALevel: btnALevel,
BtnBLevel: btnBLevel,
}
}
func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
collision := playerCollider.Check(0, 0)
if nil == collision {
return ret
}
for _, obj := range collision.Objects {
switch obj.Data.(type) {
case *Barrier:
barrierShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape)
if !overlapped {
continue
}
// ALWAY snap into hardPushbacks!
// [OverlapX, OverlapY] is the unit vector that points into the platform
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
pEffPushback.X += pushbackX
pEffPushback.Y += pushbackY
default:
}
}
return ret
}
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, inputsBuffer *RingBuffer, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame {
topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
// [WARNING] This function MUST BE called while "InputsBufferLock" is locked!
roomCapacity := len(currRenderFrame.PlayersArr)
nextRenderFramePlayers := make([]*PlayerDownsync, roomCapacity)
// Make a copy first
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
nextRenderFramePlayers[i] = &PlayerDownsync{
Id: currPlayerDownsync.Id,
VirtualGridX: currPlayerDownsync.VirtualGridX,
VirtualGridY: currPlayerDownsync.VirtualGridY,
DirX: currPlayerDownsync.DirX,
DirY: currPlayerDownsync.DirY,
VelX: currPlayerDownsync.VelX,
VelY: currPlayerDownsync.VelY,
CharacterState: currPlayerDownsync.CharacterState,
InAir: true,
Speed: currPlayerDownsync.Speed,
BattleState: currPlayerDownsync.BattleState,
Score: currPlayerDownsync.Score,
Removed: currPlayerDownsync.Removed,
JoinIndex: currPlayerDownsync.JoinIndex,
FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
Hp: currPlayerDownsync.Hp,
MaxHp: currPlayerDownsync.MaxHp,
}
if nextRenderFramePlayers[i].FramesToRecover < 0 {
nextRenderFramePlayers[i].FramesToRecover = 0
}
}
effPushbacks := make([]Vec2D, roomCapacity)
hardPushbackNorms := make([][]Vec2D, roomCapacity)
// 1. Process player inputs
if nil != delayedInputFrame {
var delayedInputFrameForPrevRenderFrame *InputFrameDownsync = nil
tmp := inputsBuffer.GetByFrameId(ConvertToInputFrameId(currRenderFrame.Id-1, inputDelayFrames, inputScaleFrames))
if nil != tmp {
delayedInputFrameForPrevRenderFrame = tmp.(*InputFrameDownsync)
}
inputList := delayedInputFrame.InputList
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
joinIndex := currPlayerDownsync.JoinIndex
thatPlayerInNextFrame := nextRenderFramePlayers[i]
if 0 < thatPlayerInNextFrame.FramesToRecover {
continue
}
decodedInput := DecodeInput(inputList[joinIndex-1])
prevBtnBLevel := int32(0)
if nil != delayedInputFrameForPrevRenderFrame {
prevDecodedInput := DecodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1])
prevBtnBLevel = prevDecodedInput.BtnBLevel
}
if decodedInput.BtnBLevel > prevBtnBLevel {
characStateAlreadyInAir := false
if ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATK1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATKED1 == thatPlayerInNextFrame.CharacterState {
characStateAlreadyInAir = true
}
characStateIsInterruptWaivable := false
if ATK_CHARACTER_STATE_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_WALKING == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState {
characStateIsInterruptWaivable = true
}
if !characStateAlreadyInAir && characStateIsInterruptWaivable {
thatPlayerInNextFrame.VelY = jumpingInitVelY
}
}
// Note that by now "0 == thatPlayerInNextFrame.FramesToRecover", we should change "CharacterState" to "WALKING" or "IDLE" depending on player inputs
if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
thatPlayerInNextFrame.DirX = decodedInput.Dx
thatPlayerInNextFrame.DirY = decodedInput.Dy
thatPlayerInNextFrame.VelX = decodedInput.Dx * currPlayerDownsync.Speed
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
}
}
}
// 2. Process player movement
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
joinIndex := currPlayerDownsync.JoinIndex
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
thatPlayerInNextFrame := nextRenderFramePlayers[i]
// Reset playerCollider position from the "virtual grid position"
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
if thatPlayerInNextFrame.VelY == jumpingInitVelY {
newVy += thatPlayerInNextFrame.VelY
}
halfColliderWidth, halfColliderHeight := currPlayerDownsync.ColliderRadius, currPlayerDownsync.ColliderRadius+currPlayerDownsync.ColliderRadius // avoid multiplying
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, virtualGridToWorldRatio)
// Update in the collision system
playerCollider.Update()
if currPlayerDownsync.InAir {
thatPlayerInNextFrame.VelX += gravityX
thatPlayerInNextFrame.VelY += gravityY
}
}
// 3. Invoke collision system stepping (no-op for backend collision lib)
// 4. Calc pushbacks for each player (after its movement) w/o bullets
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
joinIndex := currPlayerDownsync.JoinIndex
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
hardPushbackNorms[joinIndex-1] = CalcHardPushbacksNorms(playerCollider, playerShape, snapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
thatPlayerInNextFrame := nextRenderFramePlayers[i]
fallStopping := false
if collision := playerCollider.Check(0, 0); nil != collision {
for _, obj := range collision.Objects {
isBarrier, isAnotherPlayer, isBullet := false, false, false
switch obj.Data.(type) {
case *Barrier:
isBarrier = true
case *PlayerDownsync:
isAnotherPlayer = true
case *MeleeBullet:
isBullet = true
}
if isBullet {
// ignore bullets for this step
continue
}
bShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape)
if !overlapped {
continue
}
normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
landedOnGravityPushback := (snapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
if landedOnGravityPushback {
// kindly note that one player might land on top of another player, and snapping is also required in such case
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
thatPlayerInNextFrame.InAir = false
}
if isAnotherPlayer {
// [WARNING] The "zero overlap collision" might be randomly detected/missed on either frontend or backend, to have deterministic result we added paddings to all sides of a playerCollider. As each velocity component of (velX, velY) being a multiple of 0.5 at any renderFrame, each position component of (x, y) can only be a multiple of 0.5 too, thus whenever a 1-dimensional collision happens between players from [player#1: i*0.5, player#2: j*0.5, not collided yet] to [player#1: (i+k)*0.5, player#2: j*0.5, collided], the overlap becomes (i+k-j)*0.5+2*s, and after snapping subtraction the effPushback magnitude for each player is (i+k-j)*0.5, resulting in 0.5-multiples-position for the next renderFrame.
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap*2)*overlapResult.OverlapY
}
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
effPushbacks[joinIndex-1].X += pushbackX
effPushbacks[joinIndex-1].Y += pushbackY
if currPlayerDownsync.InAir && landedOnGravityPushback {
fallStopping = true
}
}
}
if fallStopping {
thatPlayerInNextFrame.VelX = 0
thatPlayerInNextFrame.VelY = 0
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.FramesToRecover = 0
}
if currPlayerDownsync.InAir {
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
switch oldNextCharacterState {
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
case ATK_CHARACTER_STATE_ATK1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
case ATK_CHARACTER_STATE_ATKED1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
}
}
}
// 7. Get players out of stuck barriers if there's any
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
joinIndex := currPlayerDownsync.JoinIndex
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
// Update "virtual grid position"
thatPlayerInNextFrame := nextRenderFramePlayers[i]
halfColliderWidth, halfColliderHeight := currPlayerDownsync.ColliderRadius, currPlayerDownsync.ColliderRadius+currPlayerDownsync.ColliderRadius // avoid multiplying
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY, worldToVirtualGridRatio)
}
return &RoomDownsyncFrame{
Id: currRenderFrame.Id + 1,
PlayersArr: nextRenderFramePlayers,
}
}

View File

@ -733,6 +733,53 @@ func (x *InputsBufferSnapshot) GetShouldForceResync() bool {
return false return false
} }
type Barrier struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Boundary *sharedprotos.Polygon2D `protobuf:"bytes,1,opt,name=boundary,proto3" json:"boundary,omitempty"`
}
func (x *Barrier) Reset() {
*x = Barrier{}
if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Barrier) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Barrier) ProtoMessage() {}
func (x *Barrier) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Barrier.ProtoReflect.Descriptor instead.
func (*Barrier) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{8}
}
func (x *Barrier) GetBoundary() *sharedprotos.Polygon2D {
if x != nil {
return x.Boundary
}
return nil
}
type MeleeBullet struct { type MeleeBullet struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -762,7 +809,7 @@ type MeleeBullet struct {
func (x *MeleeBullet) Reset() { func (x *MeleeBullet) Reset() {
*x = MeleeBullet{} *x = MeleeBullet{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[8] mi := &file_room_downsync_frame_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -775,7 +822,7 @@ func (x *MeleeBullet) String() string {
func (*MeleeBullet) ProtoMessage() {} func (*MeleeBullet) ProtoMessage() {}
func (x *MeleeBullet) ProtoReflect() protoreflect.Message { func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[8] mi := &file_room_downsync_frame_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -788,7 +835,7 @@ func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
// Deprecated: Use MeleeBullet.ProtoReflect.Descriptor instead. // Deprecated: Use MeleeBullet.ProtoReflect.Descriptor instead.
func (*MeleeBullet) Descriptor() ([]byte, []int) { func (*MeleeBullet) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{8} return file_room_downsync_frame_proto_rawDescGZIP(), []int{9}
} }
func (x *MeleeBullet) GetBattleLocalId() int32 { func (x *MeleeBullet) GetBattleLocalId() int32 {
@ -951,7 +998,7 @@ type BattleColliderInfo struct {
func (x *BattleColliderInfo) Reset() { func (x *BattleColliderInfo) Reset() {
*x = BattleColliderInfo{} *x = BattleColliderInfo{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[9] mi := &file_room_downsync_frame_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -964,7 +1011,7 @@ func (x *BattleColliderInfo) String() string {
func (*BattleColliderInfo) ProtoMessage() {} func (*BattleColliderInfo) ProtoMessage() {}
func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message { func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[9] mi := &file_room_downsync_frame_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -977,7 +1024,7 @@ func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
// Deprecated: Use BattleColliderInfo.ProtoReflect.Descriptor instead. // Deprecated: Use BattleColliderInfo.ProtoReflect.Descriptor instead.
func (*BattleColliderInfo) Descriptor() ([]byte, []int) { func (*BattleColliderInfo) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{9} return file_room_downsync_frame_proto_rawDescGZIP(), []int{10}
} }
func (x *BattleColliderInfo) GetStageName() string { func (x *BattleColliderInfo) GetStageName() string {
@ -1203,17 +1250,18 @@ type RoomDownsyncFrame struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Players map[int32]*PlayerDownsync `protobuf:"bytes,2,rep,name=players,proto3" json:"players,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` PlayersArr []*PlayerDownsync `protobuf:"bytes,2,rep,name=playersArr,proto3" json:"playersArr,omitempty"`
CountdownNanos int64 `protobuf:"varint,3,opt,name=countdownNanos,proto3" json:"countdownNanos,omitempty"` CountdownNanos int64 `protobuf:"varint,3,opt,name=countdownNanos,proto3" json:"countdownNanos,omitempty"`
MeleeBullets []*MeleeBullet `protobuf:"bytes,4,rep,name=meleeBullets,proto3" json:"meleeBullets,omitempty"` // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise MeleeBullets []*MeleeBullet `protobuf:"bytes,4,rep,name=meleeBullets,proto3" json:"meleeBullets,omitempty"` // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise
BackendUnconfirmedMask uint64 `protobuf:"varint,5,opt,name=backendUnconfirmedMask,proto3" json:"backendUnconfirmedMask,omitempty"` // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync BackendUnconfirmedMask uint64 `protobuf:"varint,5,opt,name=backendUnconfirmedMask,proto3" json:"backendUnconfirmedMask,omitempty"` // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync
ShouldForceResync bool `protobuf:"varint,6,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"` ShouldForceResync bool `protobuf:"varint,6,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"`
Players map[int32]*PlayerDownsync `protobuf:"bytes,99,rep,name=players,proto3" json:"players,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // TO BE DEPRECATED
} }
func (x *RoomDownsyncFrame) Reset() { func (x *RoomDownsyncFrame) Reset() {
*x = RoomDownsyncFrame{} *x = RoomDownsyncFrame{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[10] mi := &file_room_downsync_frame_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1226,7 +1274,7 @@ func (x *RoomDownsyncFrame) String() string {
func (*RoomDownsyncFrame) ProtoMessage() {} func (*RoomDownsyncFrame) ProtoMessage() {}
func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message { func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[10] mi := &file_room_downsync_frame_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1239,7 +1287,7 @@ func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
// Deprecated: Use RoomDownsyncFrame.ProtoReflect.Descriptor instead. // Deprecated: Use RoomDownsyncFrame.ProtoReflect.Descriptor instead.
func (*RoomDownsyncFrame) Descriptor() ([]byte, []int) { func (*RoomDownsyncFrame) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{10} return file_room_downsync_frame_proto_rawDescGZIP(), []int{11}
} }
func (x *RoomDownsyncFrame) GetId() int32 { func (x *RoomDownsyncFrame) GetId() int32 {
@ -1249,9 +1297,9 @@ func (x *RoomDownsyncFrame) GetId() int32 {
return 0 return 0
} }
func (x *RoomDownsyncFrame) GetPlayers() map[int32]*PlayerDownsync { func (x *RoomDownsyncFrame) GetPlayersArr() []*PlayerDownsync {
if x != nil { if x != nil {
return x.Players return x.PlayersArr
} }
return nil return nil
} }
@ -1284,6 +1332,13 @@ func (x *RoomDownsyncFrame) GetShouldForceResync() bool {
return false return false
} }
func (x *RoomDownsyncFrame) GetPlayers() map[int32]*PlayerDownsync {
if x != nil {
return x.Players
}
return nil
}
var File_room_downsync_frame_proto protoreflect.FileDescriptor var File_room_downsync_frame_proto protoreflect.FileDescriptor
var file_room_downsync_frame_proto_rawDesc = []byte{ var file_room_downsync_frame_proto_rawDesc = []byte{
@ -1405,7 +1460,11 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f,
0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79,
0x6e, 0x63, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x6e, 0x63, 0x22, 0x3e, 0x0a, 0x07, 0x42, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x12, 0x33, 0x0a,
0x08, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50,
0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x52, 0x08, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61,
0x72, 0x79, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c,
0x65, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61,
0x6c, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x6c, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c,
0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72,
@ -1571,32 +1630,36 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75,
0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
0x80, 0x03, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0xb8, 0x03, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e,
0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0a,
0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18,
0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e,
0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75,
0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x36,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16,
0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28,
0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65,
0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x1a, 0x52, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18,
0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x63, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70,
0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72,
0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x38, 0x01, 0x42, 0x11, 0x5a, 0x0f, 0x6a, 0x73, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x5a, 0x0f, 0x6a, 0x73,
0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -1611,7 +1674,7 @@ func file_room_downsync_frame_proto_rawDescGZIP() []byte {
return file_room_downsync_frame_proto_rawDescData return file_room_downsync_frame_proto_rawDescData
} }
var file_room_downsync_frame_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_room_downsync_frame_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
var file_room_downsync_frame_proto_goTypes = []interface{}{ var file_room_downsync_frame_proto_goTypes = []interface{}{
(*PlayerDownsync)(nil), // 0: protos.PlayerDownsync (*PlayerDownsync)(nil), // 0: protos.PlayerDownsync
(*InputFrameDecoded)(nil), // 1: protos.InputFrameDecoded (*InputFrameDecoded)(nil), // 1: protos.InputFrameDecoded
@ -1621,40 +1684,44 @@ var file_room_downsync_frame_proto_goTypes = []interface{}{
(*WsReq)(nil), // 5: protos.WsReq (*WsReq)(nil), // 5: protos.WsReq
(*WsResp)(nil), // 6: protos.WsResp (*WsResp)(nil), // 6: protos.WsResp
(*InputsBufferSnapshot)(nil), // 7: protos.InputsBufferSnapshot (*InputsBufferSnapshot)(nil), // 7: protos.InputsBufferSnapshot
(*MeleeBullet)(nil), // 8: protos.MeleeBullet (*Barrier)(nil), // 8: protos.Barrier
(*BattleColliderInfo)(nil), // 9: protos.BattleColliderInfo (*MeleeBullet)(nil), // 9: protos.MeleeBullet
(*RoomDownsyncFrame)(nil), // 10: protos.RoomDownsyncFrame (*BattleColliderInfo)(nil), // 10: protos.BattleColliderInfo
nil, // 11: protos.BattleColliderInfo.StrToVec2DListMapEntry (*RoomDownsyncFrame)(nil), // 11: protos.RoomDownsyncFrame
nil, // 12: protos.BattleColliderInfo.StrToPolygon2DListMapEntry nil, // 12: protos.BattleColliderInfo.StrToVec2DListMapEntry
nil, // 13: protos.BattleColliderInfo.MeleeSkillConfigEntry nil, // 13: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
nil, // 14: protos.RoomDownsyncFrame.PlayersEntry nil, // 14: protos.BattleColliderInfo.MeleeSkillConfigEntry
(*sharedprotos.Vec2D)(nil), // 15: sharedprotos.Vec2D nil, // 15: protos.RoomDownsyncFrame.PlayersEntry
(*sharedprotos.Vec2DList)(nil), // 16: sharedprotos.Vec2DList (*sharedprotos.Polygon2D)(nil), // 16: sharedprotos.Polygon2D
(*sharedprotos.Polygon2DList)(nil), // 17: sharedprotos.Polygon2DList (*sharedprotos.Vec2D)(nil), // 17: sharedprotos.Vec2D
(*sharedprotos.Vec2DList)(nil), // 18: sharedprotos.Vec2DList
(*sharedprotos.Polygon2DList)(nil), // 19: sharedprotos.Polygon2DList
} }
var file_room_downsync_frame_proto_depIdxs = []int32{ var file_room_downsync_frame_proto_depIdxs = []int32{
2, // 0: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync 2, // 0: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
4, // 1: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync 4, // 1: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync
10, // 2: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame 11, // 2: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame
3, // 3: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync 3, // 3: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync
9, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo 10, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
3, // 5: protos.InputsBufferSnapshot.toSendInputFrameDownsyncs:type_name -> protos.InputFrameDownsync 3, // 5: protos.InputsBufferSnapshot.toSendInputFrameDownsyncs:type_name -> protos.InputFrameDownsync
15, // 6: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D 16, // 6: protos.Barrier.boundary:type_name -> sharedprotos.Polygon2D
15, // 7: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D 17, // 7: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
11, // 8: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry 17, // 8: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
12, // 9: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry 12, // 9: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
13, // 10: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry 13, // 10: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
14, // 11: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry 14, // 11: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry
8, // 12: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet 0, // 12: protos.RoomDownsyncFrame.playersArr:type_name -> protos.PlayerDownsync
16, // 13: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList 9, // 13: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
17, // 14: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList 15, // 14: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
8, // 15: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet 18, // 15: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
0, // 16: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync 19, // 16: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
17, // [17:17] is the sub-list for method output_type 9, // 17: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet
17, // [17:17] is the sub-list for method input_type 0, // 18: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
17, // [17:17] is the sub-list for extension type_name 19, // [19:19] is the sub-list for method output_type
17, // [17:17] is the sub-list for extension extendee 19, // [19:19] is the sub-list for method input_type
0, // [0:17] is the sub-list for field type_name 19, // [19:19] is the sub-list for extension type_name
19, // [19:19] is the sub-list for extension extendee
0, // [0:19] is the sub-list for field type_name
} }
func init() { file_room_downsync_frame_proto_init() } func init() { file_room_downsync_frame_proto_init() }
@ -1760,7 +1827,7 @@ func file_room_downsync_frame_proto_init() {
} }
} }
file_room_downsync_frame_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { file_room_downsync_frame_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MeleeBullet); i { switch v := v.(*Barrier); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1772,7 +1839,7 @@ func file_room_downsync_frame_proto_init() {
} }
} }
file_room_downsync_frame_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { file_room_downsync_frame_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BattleColliderInfo); i { switch v := v.(*MeleeBullet); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1784,6 +1851,18 @@ func file_room_downsync_frame_proto_init() {
} }
} }
file_room_downsync_frame_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { file_room_downsync_frame_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BattleColliderInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_room_downsync_frame_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RoomDownsyncFrame); i { switch v := v.(*RoomDownsyncFrame); i {
case 0: case 0:
return &v.state return &v.state
@ -1802,7 +1881,7 @@ func file_room_downsync_frame_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_room_downsync_frame_proto_rawDesc, RawDescriptor: file_room_downsync_frame_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 15, NumMessages: 16,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },