Chickynoid, server authoritative character replacement

I was just about to answer your question and saw the post disappear lol. It seems you figured out a solution?

1 Like

Yeah, probably should’ve edited the original post with the solution. I’m not super confident with my fix/approach, so another person’s solution would be greatly appreciated.

To pass a String through CharacterData, here’s what I did.

I made new Read/Write functions in CharacterData:

local function WriteString(buf: buffer, offset: number, value: string): number
	local length = string.len(value)

	buffer.writeu32(buf, offset, length)     
	offset += 4
	buffer.writestring(buf, offset, value, length) 
	offset += length

	return offset
end

local function ReadString(buf: buffer, offset: number)
	local length = buffer.readu32(buf, offset)  
	offset += 4
	local str = buffer.readstring(buf, offset, length) 
	offset += length
	
	return str, offset
end

local function CompareString(a, b)
	return a == b
end

local function ValidateString(input)
	return input
end

I added a new Method to CharacterData:ModuleSetup()

CharacterData.methods["String"] = {
		write = WriteString,
		read = ReadString,
		validate = ValidateString,
		compare = CompareString,
	}

The buffer had a limit of 64 bytes, so I increased the limit to 128 in ServerSnapshotGen:

local smallBufferSize = 128

It wasn’t working for some reason at this point, but commenting out some checks in this function seemed to fix it. I don’t really know what this check did, so if it’s an important check or theres a reason why it wasn’t passing the check, then that’d be great information to know.

function CharacterData:DeserializeFromBitBuffer(buf : buffer, offset: number)
	
	local contentBits = buffer.readu16(buf, offset)
	offset+=2
	
	local bitIndex = 0
	for keyIndex, key in CharacterData.keys do
		
		
		local value = self.serialized[key]
		--local hasBit = bit32.band(contentBits, bit32.lshift(1, bitIndex)) > 0
		
		--if hasBit then
            local func = CharacterData.methods[CharacterData.packFunctions[key]]
            self.serialized[key],offset  = func.read(buf, offset)
		--end
		bitIndex += 1
	end
	return offset
end

All of this let me pass a string through CharacterData as a serialized value.

1 Like

How can I send tables through simulation.state in a way that it gets automatically replicated to the Client when modified serverside?

Let’s say I wanted to have a table of active speed buffs in order to change the walk speed. It has to be in table format so these speed buffs can be identified and “expire.”

If, on the server, a speed buff of “3” was added to the SpeedBuff table in simulation.state, how can I replicate this to the client? As of now, the buff is added to the server table and speed is applied, but the Client can’t see the speed buff because it is never added to their table.

image

If this isn’t practical or doable with the state table, how else could I do it?

For my game what I did was make a server and client module to manage the effects/buffs. Server module to keep track of all the buffs, calculate any of the changes, and send an event to the client to let them know what effects to play and to update gui. My client module keeps track of all of the effects to play on each character.

In Simulation, I added this effect table (these are the only values that the server mod I made changes), and the values in them act as multipliers. I also have one that enables a move type, levitation.

Just make sure if you add any new tables to Simulation that you add them here:

Idk if I explained properly lol, but if you’d like I could send you the modules and you can adapt them to your game how you’d like just lmk.

1 Like

I didn’t know you could add new tables like that. Nice approach, I will use this in my project!

I do like this method but I also figured out why recursive tables weren’t being replicated properly.

The DeltaTable :MakeDeltaTable() function wasn’t recognizing changes in table keys or values, and didn’t send any changes to the client as a result.

I’m in desperate search of a way to change Hitbox size, and this seems to be very close to what I’m looking for. Not to mention it seems like it detects MeshParts more accurately and runs better too.

it has some quirks that would personally prevent me from using it in any actual game.

What are some of the limitations/quirks you noticed while using the BlockCast approach to Collision? Are they specific to the game’s environment (Smooth Terrain vs. MeshParts vs. BaseParts), or are they general bugs/inconsistencies that make it unreliable everywhere?

I’ve implemented it into my game and it seems to run okay, I’m just curious if there any specific scenarios where it doesn’t work as intended (my game is made up of mostly flat BaseParts). The only one I have noticed so far is the Rotated BasePart issue, which I can easily fix by running math.ceil() on Orientations in :MakeWorld().

At certain angles you can still phase through and into walls especially if you manage to wedge yourself into a corner. I’m sure it could be improved with some more effort but I’ve decided to wait until margins are added, if ever, to continue.

1 Like

Yeah, the only issue I’ve seem to come across is interactions with < 90 degree corners; everything else seems to work just fine.

Is this an issue that is inherently caused by the lack of margins?

Yeah its due to the lack of margins. I tried to mitigate it by starting the shapecast further back partially inside the character but it isn’t perfect. You can increase the shiftback distance to make things more consistent but then you get some weird collisions in certain cases. I’ve been thinking about a way to make it more consistent and I have something in mind so I may revisit things and see.

1 Like